svn:eol-style native
authorAlexandre Emsenhuber <ialex@users.mediawiki.org>
Sun, 19 Jul 2009 12:27:48 +0000 (12:27 +0000)
committerAlexandre Emsenhuber <ialex@users.mediawiki.org>
Sun, 19 Jul 2009 12:27:48 +0000 (12:27 +0000)
48 files changed:
js2/mwEmbed/binPlayers/omtk-fx/LICENSE.txt
js2/mwEmbed/binPlayers/omtk-fx/README.txt
js2/mwEmbed/binPlayers/omtk-fx/src/as/Player.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/EndOfOggStreamError.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/LogicalOggStream.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/OggPacket.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/OggPage.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/ogg/UncachedUrlStream.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/util/BitByteArray.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/util/HuffmanNode.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/AudioPacket.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/CodeBook.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/CommentHeader.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Floor.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Floor0.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Floor1.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/IdentificationHeader.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Look.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mapping.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mapping0.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mdct.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Mode.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Residue.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Residue2.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/SetupHeader.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/Util.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/VorbisSound.as
js2/mwEmbed/binPlayers/omtk-fx/src/as/org/omtk/vorbis/VorbisStream.as
js2/mwEmbed/binPlayers/omtk-fx/src/haXe/org/omtk/vorbis/MdctHX.hx
js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan-zh-hant.srt
js2/mwEmbed/example_usage/media/princess_archive_org/princess_iron_fan.srt
js2/mwEmbed/jquery/plugins/jquery.pngFix.js
js2/mwEmbed/libClipEdit/colorpicker/css/layout.css
js2/mwEmbed/libClipEdit/colorpicker/index.html
js2/mwEmbed/libClipEdit/colorpicker/js/colorpicker.js
js2/mwEmbed/libClipEdit/colorpicker/js/eye.js
js2/mwEmbed/libClipEdit/colorpicker/js/layout.js
js2/mwEmbed/libClipEdit/colorpicker/js/utils.js
js2/mwEmbed/libClipEdit/pixastic-editor/editor.js
js2/mwEmbed/libClipEdit/pixastic-editor/pixastic.all.js
js2/mwEmbed/libClipEdit/pixastic-editor/pixastic.css
js2/mwEmbed/libClipEdit/pixastic-editor/ui.js
js2/mwEmbed/libClipEdit/pixastic-editor/uidata.js
js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/editor.js
js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/pixastic.all.js
js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/pixastic.css
js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/ui.js
js2/mwEmbed/libClipEdit/pixastic-lib/pixastic-editor/uidata.js

index 6b1065b..878ca2a 100644 (file)
-                                 Apache License\r
-                           Version 2.0, January 2004\r
-                        http://www.apache.org/licenses/\r
-\r
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r
-\r
-   1. Definitions.\r
-\r
-      "License" shall mean the terms and conditions for use, reproduction,\r
-      and distribution as defined by Sections 1 through 9 of this document.\r
-\r
-      "Licensor" shall mean the copyright owner or entity authorized by\r
-      the copyright owner that is granting the License.\r
-\r
-      "Legal Entity" shall mean the union of the acting entity and all\r
-      other entities that control, are controlled by, or are under common\r
-      control with that entity. For the purposes of this definition,\r
-      "control" means (i) the power, direct or indirect, to cause the\r
-      direction or management of such entity, whether by contract or\r
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r
-      outstanding shares, or (iii) beneficial ownership of such entity.\r
-\r
-      "You" (or "Your") shall mean an individual or Legal Entity\r
-      exercising permissions granted by this License.\r
-\r
-      "Source" form shall mean the preferred form for making modifications,\r
-      including but not limited to software source code, documentation\r
-      source, and configuration files.\r
-\r
-      "Object" form shall mean any form resulting from mechanical\r
-      transformation or translation of a Source form, including but\r
-      not limited to compiled object code, generated documentation,\r
-      and conversions to other media types.\r
-\r
-      "Work" shall mean the work of authorship, whether in Source or\r
-      Object form, made available under the License, as indicated by a\r
-      copyright notice that is included in or attached to the work\r
-      (an example is provided in the Appendix below).\r
-\r
-      "Derivative Works" shall mean any work, whether in Source or Object\r
-      form, that is based on (or derived from) the Work and for which the\r
-      editorial revisions, annotations, elaborations, or other modifications\r
-      represent, as a whole, an original work of authorship. For the purposes\r
-      of this License, Derivative Works shall not include works that remain\r
-      separable from, or merely link (or bind by name) to the interfaces of,\r
-      the Work and Derivative Works thereof.\r
-\r
-      "Contribution" shall mean any work of authorship, including\r
-      the original version of the Work and any modifications or additions\r
-      to that Work or Derivative Works thereof, that is intentionally\r
-      submitted to Licensor for inclusion in the Work by the copyright owner\r
-      or by an individual or Legal Entity authorized to submit on behalf of\r
-      the copyright owner. For the purposes of this definition, "submitted"\r
-      means any form of electronic, verbal, or written communication sent\r
-      to the Licensor or its representatives, including but not limited to\r
-      communication on electronic mailing lists, source code control systems,\r
-      and issue tracking systems that are managed by, or on behalf of, the\r
-      Licensor for the purpose of discussing and improving the Work, but\r
-      excluding communication that is conspicuously marked or otherwise\r
-      designated in writing by the copyright owner as "Not a Contribution."\r
-\r
-      "Contributor" shall mean Licensor and any individual or Legal Entity\r
-      on behalf of whom a Contribution has been received by Licensor and\r
-      subsequently incorporated within the Work.\r
-\r
-   2. Grant of Copyright License. Subject to the terms and conditions of\r
-      this License, each Contributor hereby grants to You a perpetual,\r
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
-      copyright license to reproduce, prepare Derivative Works of,\r
-      publicly display, publicly perform, sublicense, and distribute the\r
-      Work and such Derivative Works in Source or Object form.\r
-\r
-   3. Grant of Patent License. Subject to the terms and conditions of\r
-      this License, each Contributor hereby grants to You a perpetual,\r
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
-      (except as stated in this section) patent license to make, have made,\r
-      use, offer to sell, sell, import, and otherwise transfer the Work,\r
-      where such license applies only to those patent claims licensable\r
-      by such Contributor that are necessarily infringed by their\r
-      Contribution(s) alone or by combination of their Contribution(s)\r
-      with the Work to which such Contribution(s) was submitted. If You\r
-      institute patent litigation against any entity (including a\r
-      cross-claim or counterclaim in a lawsuit) alleging that the Work\r
-      or a Contribution incorporated within the Work constitutes direct\r
-      or contributory patent infringement, then any patent licenses\r
-      granted to You under this License for that Work shall terminate\r
-      as of the date such litigation is filed.\r
-\r
-   4. Redistribution. You may reproduce and distribute copies of the\r
-      Work or Derivative Works thereof in any medium, with or without\r
-      modifications, and in Source or Object form, provided that You\r
-      meet the following conditions:\r
-\r
-      (a) You must give any other recipients of the Work or\r
-          Derivative Works a copy of this License; and\r
-\r
-      (b) You must cause any modified files to carry prominent notices\r
-          stating that You changed the files; and\r
-\r
-      (c) You must retain, in the Source form of any Derivative Works\r
-          that You distribute, all copyright, patent, trademark, and\r
-          attribution notices from the Source form of the Work,\r
-          excluding those notices that do not pertain to any part of\r
-          the Derivative Works; and\r
-\r
-      (d) If the Work includes a "NOTICE" text file as part of its\r
-          distribution, then any Derivative Works that You distribute must\r
-          include a readable copy of the attribution notices contained\r
-          within such NOTICE file, excluding those notices that do not\r
-          pertain to any part of the Derivative Works, in at least one\r
-          of the following places: within a NOTICE text file distributed\r
-          as part of the Derivative Works; within the Source form or\r
-          documentation, if provided along with the Derivative Works; or,\r
-          within a display generated by the Derivative Works, if and\r
-          wherever such third-party notices normally appear. The contents\r
-          of the NOTICE file are for informational purposes only and\r
-          do not modify the License. You may add Your own attribution\r
-          notices within Derivative Works that You distribute, alongside\r
-          or as an addendum to the NOTICE text from the Work, provided\r
-          that such additional attribution notices cannot be construed\r
-          as modifying the License.\r
-\r
-      You may add Your own copyright statement to Your modifications and\r
-      may provide additional or different license terms and conditions\r
-      for use, reproduction, or distribution of Your modifications, or\r
-      for any such Derivative Works as a whole, provided Your use,\r
-      reproduction, and distribution of the Work otherwise complies with\r
-      the conditions stated in this License.\r
-\r
-   5. Submission of Contributions. Unless You explicitly state otherwise,\r
-      any Contribution intentionally submitted for inclusion in the Work\r
-      by You to the Licensor shall be under the terms and conditions of\r
-      this License, without any additional terms or conditions.\r
-      Notwithstanding the above, nothing herein shall supersede or modify\r
-      the terms of any separate license agreement you may have executed\r
-      with Licensor regarding such Contributions.\r
-\r
-   6. Trademarks. This License does not grant permission to use the trade\r
-      names, trademarks, service marks, or product names of the Licensor,\r
-      except as required for reasonable and customary use in describing the\r
-      origin of the Work and reproducing the content of the NOTICE file.\r
-\r
-   7. Disclaimer of Warranty. Unless required by applicable law or\r
-      agreed to in writing, Licensor provides the Work (and each\r
-      Contributor provides its Contributions) on an "AS IS" BASIS,\r
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r
-      implied, including, without limitation, any warranties or conditions\r
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r
-      PARTICULAR PURPOSE. You are solely responsible for determining the\r
-      appropriateness of using or redistributing the Work and assume any\r
-      risks associated with Your exercise of permissions under this License.\r
-\r
-   8. Limitation of Liability. In no event and under no legal theory,\r
-      whether in tort (including negligence), contract, or otherwise,\r
-      unless required by applicable law (such as deliberate and grossly\r
-      negligent acts) or agreed to in writing, shall any Contributor be\r
-      liable to You for damages, including any direct, indirect, special,\r
-      incidental, or consequential damages of any character arising as a\r
-      result of this License or out of the use or inability to use the\r
-      Work (including but not limited to damages for loss of goodwill,\r
-      work stoppage, computer failure or malfunction, or any and all\r
-      other commercial damages or losses), even if such Contributor\r
-      has been advised of the possibility of such damages.\r
-\r
-   9. Accepting Warranty or Additional Liability. While redistributing\r
-      the Work or Derivative Works thereof, You may choose to offer,\r
-      and charge a fee for, acceptance of support, warranty, indemnity,\r
-      or other liability obligations and/or rights consistent with this\r
-      License. However, in accepting such obligations, You may act only\r
-      on Your own behalf and on Your sole responsibility, not on behalf\r
-      of any other Contributor, and only if You agree to indemnify,\r
-      defend, and hold each Contributor harmless for any liability\r
-      incurred by, or claims asserted against, such Contributor by reason\r
-      of your accepting any such warranty or additional liability.\r
-\r
-   END OF TERMS AND CONDITIONS\r
-\r
-   APPENDIX: How to apply the Apache License to your work.\r
-\r
-      To apply the Apache License to your work, attach the following\r
-      boilerplate notice, with the fields enclosed by brackets "[]"\r
-      replaced with your own identifying information. (Don't include\r
-      the brackets!)  The text should be enclosed in the appropriate\r
-      comment syntax for the file format. We also recommend that a\r
-      file or class name and description of purpose be included on the\r
-      same "printed page" as the copyright notice for easier\r
-      identification within third-party archives.\r
-\r
-   Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
index 2c421f2..f8416e0 100644 (file)
@@ -1,17 +1,17 @@
-\r
- *** PRELIMINARY SOFTWARE ***\r
\r
-Please note that this is a prerelease of the OMTK Flash library. No\r
-quality of this software can be guaranteed.\r
-\r
-\r
- *** haXe notes ***\r
\r
-You need at least haXe 2.01 (with support for the new Flash 10 types)\r
-to compile the haXe source.\r
-\r
- *** Flash notes ***\r
\r
-I am not able to create a .SWC library from the haXe .SWF file. It's\r
-therefore dynamically linked at runtime and hxmdct.swf must be placed\r
-in the same directory as the "real" Flash movie.\r
+
+ *** PRELIMINARY SOFTWARE ***
+Please note that this is a prerelease of the OMTK Flash library. No
+quality of this software can be guaranteed.
+
+
+ *** haXe notes ***
+You need at least haXe 2.01 (with support for the new Flash 10 types)
+to compile the haXe source.
+
+ *** Flash notes ***
+I am not able to create a .SWC library from the haXe .SWF file. It's
+therefore dynamically linked at runtime and hxmdct.swf must be placed
+in the same directory as the "real" Flash movie.
index 3650517..6abe5d2 100644 (file)
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package {\r
-\r
-       import org.omtk.vorbis.VorbisSound;\r
-       \r
-       import flash.display.Shape;\r
-       import flash.display.Sprite;\r
-       import flash.display.StageAlign;\r
-       import flash.display.StageQuality;\r
-       import flash.display.StageScaleMode;\r
-       import flash.net.*;\r
-       import flash.events.Event;\r
-       import flash.text.TextField;\r
-       import flash.utils.ByteArray;\r
-       import flash.utils.Endian;\r
-       import flash.utils.getTimer;\r
-       import flash.utils.setTimeout;\r
-       import flash.utils.setInterval;\r
-       import flash.external.ExternalInterface;\r
-       \r
-       [ SWF( backgroundColor = '#ffffff', width = '1', height = '1' ) ]\r
-       \r
-       public class Player extends Sprite {\r
-       \r
-               private var sound: VorbisSound;\r
-               private var initialized: Boolean = false;\r
-               \r
-               public function Player() {\r
-                       if(stage != null) {\r
-                               stage.frameRate = 20;\r
-                       }\r
-                       \r
-                       setTimeout(registerJSCallbacks, 100);\r
-                       initialized = true;\r
-               }\r
-\r
-               private function registerJSCallbacks(): void {\r
-                       if (ExternalInterface.available) {\r
-                               ExternalInterface.addCallback("play", playJS);\r
-                               ExternalInterface.addCallback("getMetaData", getMetaDataJS);\r
-                               ExternalInterface.addCallback("getPosition", getPositionJS);            \r
-                       }\r
-               }\r
-\r
-               public function playJS(url: String): void {\r
-                       if(sound != null) {\r
-                               sound.stop();\r
-                       }\r
-                       sound = new VorbisSound(new URLRequest(url));\r
-                       sound.addEventListener(Event.COMPLETE, complete);       \r
-                       sound.addEventListener(VorbisSound.METADATA_UPDATE, metadataUpdate);\r
-                       sound.play();\r
-               }\r
-\r
-               public function getMetaDataJS(key: String): String {\r
-                       if(sound == null) {\r
-                               return null;\r
-                       }\r
-                       else {\r
-                               return sound.getMetaData(key);\r
-                       }\r
-               }\r
-               \r
-               public function getPositionJS(): int {\r
-                       if(sound == null) {\r
-                               return -1;\r
-                       }\r
-                       else {\r
-                               return sound.position;\r
-                       }\r
-               }\r
-               \r
-               private function complete(event: Event):void {\r
-                       trace("complete");\r
-                       if(ExternalInterface.available) {\r
-                               ExternalInterface.call("OMTK_P_complete");\r
-                       }\r
-               }\r
-\r
-               private function metadataUpdate(event: Event):void {\r
-                       trace("metadata update: " + sound.getMetaData("TITLE"));\r
-                       if(ExternalInterface.available) {\r
-                               ExternalInterface.call("OMTK_P_metadataUpdate");\r
-                       }\r
-               }\r
-\r
-       }\r
-       \r
-}\r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package {
+
+       import org.omtk.vorbis.VorbisSound;
+       
+       import flash.display.Shape;
+       import flash.display.Sprite;
+       import flash.display.StageAlign;
+       import flash.display.StageQuality;
+       import flash.display.StageScaleMode;
+       import flash.net.*;
+       import flash.events.Event;
+       import flash.text.TextField;
+       import flash.utils.ByteArray;
+       import flash.utils.Endian;
+       import flash.utils.getTimer;
+       import flash.utils.setTimeout;
+       import flash.utils.setInterval;
+       import flash.external.ExternalInterface;
+       
+       [ SWF( backgroundColor = '#ffffff', width = '1', height = '1' ) ]
+       
+       public class Player extends Sprite {
+       
+               private var sound: VorbisSound;
+               private var initialized: Boolean = false;
+               
+               public function Player() {
+                       if(stage != null) {
+                               stage.frameRate = 20;
+                       }
+                       
+                       setTimeout(registerJSCallbacks, 100);
+                       initialized = true;
+               }
+
+               private function registerJSCallbacks(): void {
+                       if (ExternalInterface.available) {
+                               ExternalInterface.addCallback("play", playJS);
+                               ExternalInterface.addCallback("getMetaData", getMetaDataJS);
+                               ExternalInterface.addCallback("getPosition", getPositionJS);            
+                       }
+               }
+
+               public function playJS(url: String): void {
+                       if(sound != null) {
+                               sound.stop();
+                       }
+                       sound = new VorbisSound(new URLRequest(url));
+                       sound.addEventListener(Event.COMPLETE, complete);       
+                       sound.addEventListener(VorbisSound.METADATA_UPDATE, metadataUpdate);
+                       sound.play();
+               }
+
+               public function getMetaDataJS(key: String): String {
+                       if(sound == null) {
+                               return null;
+                       }
+                       else {
+                               return sound.getMetaData(key);
+                       }
+               }
+               
+               public function getPositionJS(): int {
+                       if(sound == null) {
+                               return -1;
+                       }
+                       else {
+                               return sound.position;
+                       }
+               }
+               
+               private function complete(event: Event):void {
+                       trace("complete");
+                       if(ExternalInterface.available) {
+                               ExternalInterface.call("OMTK_P_complete");
+                       }
+               }
+
+               private function metadataUpdate(event: Event):void {
+                       trace("metadata update: " + sound.getMetaData("TITLE"));
+                       if(ExternalInterface.available) {
+                               ExternalInterface.call("OMTK_P_metadataUpdate");
+                       }
+               }
+
+       }
+       
+}
index 3c02799..9b8a82a 100644 (file)
@@ -1,29 +1,29 @@
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.ogg {\r
-\r
-       public class EndOfOggStreamError extends Error {\r
-       \r
-               public function EndOfOggStreamError(message:String = null) {\r
-                       super(message);\r
-               }\r
-       \r
-       }\r
-\r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.ogg {
+
+       public class EndOfOggStreamError extends Error {
+       
+               public function EndOfOggStreamError(message:String = null) {
+                       super(message);
+               }
+       
+       }
+
 }
\ No newline at end of file
index a568559..d9d5d35 100644 (file)
@@ -1,72 +1,72 @@
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.ogg {\r
-\r
-       import org.omtk.util.BitByteArray;      \r
-       import flash.utils.Endian;\r
-\r
-       public class LogicalOggStream {\r
-       \r
-               private var source:UncachedUrlStream;\r
-               \r
-               private var pageIndex:int;\r
-               private var currentPage:OggPage;\r
-               private var currentSegmentIndex:int;\r
-               \r
-               public function LogicalOggStream(source:UncachedUrlStream) {\r
-                       this.source = source;\r
-               }\r
-               \r
-               public function getNextOggPacket(): OggPacket {\r
-               \r
-                       var res:BitByteArray = new BitByteArray();\r
-\r
-                       var segmentLength:int = 0;\r
-\r
-                       if(currentPage == null) {\r
-                               currentPage = source.getNextOggPage();\r
-                       }\r
-\r
-                       do {\r
-                               if(currentSegmentIndex >= currentPage.segmentOffsets.length) {\r
-                       currentSegmentIndex=0;\r
-\r
-                       if(currentPage.eos) {\r
-                               throw new EndOfOggStreamError("End of OGG stream");\r
-                       }\r
-                       \r
-                               currentPage = source.getNextOggPage();\r
-                               }\r
-\r
-                               segmentLength = currentPage.segmentLengths[currentSegmentIndex];\r
-                               res.writeBytes(currentPage.data, currentPage.segmentOffsets[currentSegmentIndex], segmentLength);\r
-                               currentSegmentIndex++;\r
-                       }\r
-                       while(segmentLength==255);\r
-                       \r
-                       res.position = 0;\r
-                       \r
-                       var lastPacket: Boolean = currentPage.eos && currentSegmentIndex == currentPage.segmentOffsets.length;\r
-                       var lastGranulePosition: int = currentPage.absoluteGranulePosition;\r
-                       \r
-                       return new OggPacket(res, lastPacket, lastGranulePosition);\r
-               }\r
-       \r
-       }\r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.ogg {
+
+       import org.omtk.util.BitByteArray;      
+       import flash.utils.Endian;
+
+       public class LogicalOggStream {
+       
+               private var source:UncachedUrlStream;
+               
+               private var pageIndex:int;
+               private var currentPage:OggPage;
+               private var currentSegmentIndex:int;
+               
+               public function LogicalOggStream(source:UncachedUrlStream) {
+                       this.source = source;
+               }
+               
+               public function getNextOggPacket(): OggPacket {
+               
+                       var res:BitByteArray = new BitByteArray();
+
+                       var segmentLength:int = 0;
+
+                       if(currentPage == null) {
+                               currentPage = source.getNextOggPage();
+                       }
+
+                       do {
+                               if(currentSegmentIndex >= currentPage.segmentOffsets.length) {
+                       currentSegmentIndex=0;
+
+                       if(currentPage.eos) {
+                               throw new EndOfOggStreamError("End of OGG stream");
+                       }
+                       
+                               currentPage = source.getNextOggPage();
+                               }
+
+                               segmentLength = currentPage.segmentLengths[currentSegmentIndex];
+                               res.writeBytes(currentPage.data, currentPage.segmentOffsets[currentSegmentIndex], segmentLength);
+                               currentSegmentIndex++;
+                       }
+                       while(segmentLength==255);
+                       
+                       res.position = 0;
+                       
+                       var lastPacket: Boolean = currentPage.eos && currentSegmentIndex == currentPage.segmentOffsets.length;
+                       var lastGranulePosition: int = currentPage.absoluteGranulePosition;
+                       
+                       return new OggPacket(res, lastPacket, lastGranulePosition);
+               }
+       
+       }
 }
\ No newline at end of file
index 95b53f5..b7876ca 100644 (file)
@@ -1,49 +1,49 @@
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.ogg {\r
-\r
-       import org.omtk.util.BitByteArray;\r
-\r
-       public class OggPacket {\r
-       \r
-               private var _data: BitByteArray;\r
-               private var _lastPacket: Boolean;\r
-               private var _lastGranulePosition: int;\r
-               \r
-               public function OggPacket(data: BitByteArray, lastPacket: Boolean, lastGranulePosition: int) {\r
-                       _data = data;\r
-                       _lastPacket = lastPacket;\r
-                       _lastGranulePosition = lastGranulePosition;\r
-               }\r
-       \r
-               public function get data(): BitByteArray {\r
-                       return _data;\r
-               }\r
-               \r
-               public function get lastPacket(): Boolean {\r
-                       return _lastPacket;\r
-               }\r
-               \r
-               public function get lastGranulePosition(): int {\r
-                       return _lastGranulePosition;\r
-               }\r
-       \r
-       }\r
-       \r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.ogg {
+
+       import org.omtk.util.BitByteArray;
+
+       public class OggPacket {
+       
+               private var _data: BitByteArray;
+               private var _lastPacket: Boolean;
+               private var _lastGranulePosition: int;
+               
+               public function OggPacket(data: BitByteArray, lastPacket: Boolean, lastGranulePosition: int) {
+                       _data = data;
+                       _lastPacket = lastPacket;
+                       _lastGranulePosition = lastGranulePosition;
+               }
+       
+               public function get data(): BitByteArray {
+                       return _data;
+               }
+               
+               public function get lastPacket(): Boolean {
+                       return _lastPacket;
+               }
+               
+               public function get lastGranulePosition(): int {
+                       return _lastGranulePosition;
+               }
+       
+       }
+       
 }
\ No newline at end of file
index 54f6387..8e90b08 100644 (file)
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.ogg {\r
-\r
-       import flash.net.*;\r
-       import flash.utils.ByteArray;\r
-       \r
-       public class OggPage {\r
-\r
-               private var _version:int;\r
-               private var _continued:Boolean;\r
-               private var _bos:Boolean;\r
-               private var _eos:Boolean;\r
-               private var _absoluteGranulePosition:int;\r
-               private var _streamSerialNumber:int;\r
-               private var _pageSequenceNumber:int;\r
-               private var _pageCheckSum:int;\r
-               private var _segmentOffsets:Array;\r
-               private var _segmentLengths:Array;\r
-               private var _totalLength:int;\r
-               private var _data:ByteArray;\r
-                       \r
-               public function OggPage(stream:URLStream) {\r
-\r
-                       var capture:int = stream.readInt();\r
-                       if(capture != 0x5367674f) {\r
-                               throw new Error("Ogg page does not start with 'OggS': "+capture);\r
-                       }\r
-               \r
-                       _version = stream.readByte()&0xff;\r
-                       var tmp:int = stream.readByte();\r
-               \r
-                       _continued = (tmp&1)!=0;;\r
-                       _bos = (tmp&2)!=0;\r
-                       _eos = (tmp&4)!=0;\r
-                       \r
-                       // absoluteGranulePosition is really 64 bits\r
-                       _absoluteGranulePosition = stream.readUnsignedInt();\r
-                       stream.readUnsignedInt(); // last 32 bits of _absoluteGranulePosition\r
-                       \r
-                       _streamSerialNumber = stream.readUnsignedInt();\r
-                       _pageSequenceNumber = stream.readUnsignedInt();\r
-                       _pageCheckSum = stream.readUnsignedInt();\r
-                       \r
-                       //trace("_pageSequenceNumber: " + _pageSequenceNumber);\r
-                       \r
-                       var pageSegments:int = stream.readUnsignedByte();\r
-                       \r
-                       //stream.waitFor(pageSegments);\r
-                       \r
-                       _segmentOffsets = [];\r
-                       _segmentLengths = [];\r
-                       _data = new ByteArray();\r
-                       \r
-                       var totalLength:int;\r
-                       \r
-                       var i:int;\r
-                       var l:int;\r
-                       \r
-                       for( i= 0 ; i < pageSegments ; i++ ) {\r
-                               l = stream.readUnsignedByte();\r
-                               _segmentLengths.push( l );\r
-                               _segmentOffsets.push( totalLength );\r
-                               totalLength += l;\r
-                       }       \r
-                       \r
-                       stream.readBytes(_data, 0, totalLength);\r
-               }\r
-       \r
-               public function get absoluteGranulePosition():int {\r
-                       return _absoluteGranulePosition;\r
-               }\r
-\r
-               public function get segmentOffsets():Array {\r
-                       return _segmentOffsets;\r
-               }\r
-               \r
-               public function get segmentLengths():Array {\r
-                       return _segmentLengths;\r
-               }\r
-               \r
-               public function get data():ByteArray {\r
-                       return _data;\r
-               }\r
-\r
-               public function get eos():Boolean {\r
-                       return _eos;\r
-               }\r
-               \r
-               public function get bos():Boolean {\r
-                       return _bos;\r
-               }\r
-               \r
-               public function get continued():Boolean {\r
-                       return _continued;\r
-               }\r
-               \r
-       }\r
-\r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.ogg {
+
+       import flash.net.*;
+       import flash.utils.ByteArray;
+       
+       public class OggPage {
+
+               private var _version:int;
+               private var _continued:Boolean;
+               private var _bos:Boolean;
+               private var _eos:Boolean;
+               private var _absoluteGranulePosition:int;
+               private var _streamSerialNumber:int;
+               private var _pageSequenceNumber:int;
+               private var _pageCheckSum:int;
+               private var _segmentOffsets:Array;
+               private var _segmentLengths:Array;
+               private var _totalLength:int;
+               private var _data:ByteArray;
+                       
+               public function OggPage(stream:URLStream) {
+
+                       var capture:int = stream.readInt();
+                       if(capture != 0x5367674f) {
+                               throw new Error("Ogg page does not start with 'OggS': "+capture);
+                       }
+               
+                       _version = stream.readByte()&0xff;
+                       var tmp:int = stream.readByte();
+               
+                       _continued = (tmp&1)!=0;;
+                       _bos = (tmp&2)!=0;
+                       _eos = (tmp&4)!=0;
+                       
+                       // absoluteGranulePosition is really 64 bits
+                       _absoluteGranulePosition = stream.readUnsignedInt();
+                       stream.readUnsignedInt(); // last 32 bits of _absoluteGranulePosition
+                       
+                       _streamSerialNumber = stream.readUnsignedInt();
+                       _pageSequenceNumber = stream.readUnsignedInt();
+                       _pageCheckSum = stream.readUnsignedInt();
+                       
+                       //trace("_pageSequenceNumber: " + _pageSequenceNumber);
+                       
+                       var pageSegments:int = stream.readUnsignedByte();
+                       
+                       //stream.waitFor(pageSegments);
+                       
+                       _segmentOffsets = [];
+                       _segmentLengths = [];
+                       _data = new ByteArray();
+                       
+                       var totalLength:int;
+                       
+                       var i:int;
+                       var l:int;
+                       
+                       for( i= 0 ; i < pageSegments ; i++ ) {
+                               l = stream.readUnsignedByte();
+                               _segmentLengths.push( l );
+                               _segmentOffsets.push( totalLength );
+                               totalLength += l;
+                       }       
+                       
+                       stream.readBytes(_data, 0, totalLength);
+               }
+       
+               public function get absoluteGranulePosition():int {
+                       return _absoluteGranulePosition;
+               }
+
+               public function get segmentOffsets():Array {
+                       return _segmentOffsets;
+               }
+               
+               public function get segmentLengths():Array {
+                       return _segmentLengths;
+               }
+               
+               public function get data():ByteArray {
+                       return _data;
+               }
+
+               public function get eos():Boolean {
+                       return _eos;
+               }
+               
+               public function get bos():Boolean {
+                       return _bos;
+               }
+               
+               public function get continued():Boolean {
+                       return _continued;
+               }
+               
+       }
+
 }
\ No newline at end of file
index 30fc448..6e4a34a 100644 (file)
@@ -1,52 +1,52 @@
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.ogg {\r
-\r
-       import flash.net.*;\r
-       import flash.utils.Endian;\r
-       import flash.events.HTTPStatusEvent;\r
-       import flash.events.ProgressEvent;\r
-       \r
-       public class UncachedUrlStream {\r
-               \r
-               private var source:URLStream;\r
-       \r
-               public function UncachedUrlStream(source: URLStream) {\r
-                       this.source = source;\r
-               }\r
-       \r
-               public function get bytesAvailable():int {\r
-                       return source.bytesAvailable;\r
-               }       \r
-       \r
-               public function addEventListener(type:String, listener:Function):void {\r
-                       source.addEventListener(type, listener);\r
-               }\r
-       \r
-               public function getLogicalOggStream():LogicalOggStream {\r
-                       return new LogicalOggStream(this);\r
-               }\r
-       \r
-               public function getNextOggPage():OggPage {\r
-                       return new OggPage(source);\r
-               }\r
-               \r
-       }\r
-\r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.ogg {
+
+       import flash.net.*;
+       import flash.utils.Endian;
+       import flash.events.HTTPStatusEvent;
+       import flash.events.ProgressEvent;
+       
+       public class UncachedUrlStream {
+               
+               private var source:URLStream;
+       
+               public function UncachedUrlStream(source: URLStream) {
+                       this.source = source;
+               }
+       
+               public function get bytesAvailable():int {
+                       return source.bytesAvailable;
+               }       
+       
+               public function addEventListener(type:String, listener:Function):void {
+                       source.addEventListener(type, listener);
+               }
+       
+               public function getLogicalOggStream():LogicalOggStream {
+                       return new LogicalOggStream(this);
+               }
+       
+               public function getNextOggPage():OggPage {
+                       return new OggPage(source);
+               }
+               
+       }
+
 }
\ No newline at end of file
index d954897..3c54f6f 100644 (file)
@@ -1,75 +1,75 @@
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.util {\r
-\r
-       import flash.utils.ByteArray;\r
-       import flash.utils.Endian;\r
-       import flash.errors.IllegalOperationError;\r
-       \r
-       public class BitByteArray extends ByteArray {\r
-       \r
-               private var currentByte:uint;\r
-               private var bitIndex:int = 8;\r
-       \r
-               public function BitByteArray() {\r
-                       this.endian = Endian.LITTLE_ENDIAN;\r
-               }\r
-\r
-               public function readBit():Boolean {\r
-                       if (bitIndex > 7) {\r
-                               bitIndex = 0;\r
-                               currentByte = readUnsignedByte();\r
-                       }\r
-                       return (currentByte & (1 << (bitIndex++))) != 0;\r
-               }\r
-               \r
-               public function readUnsignedBitwiseInt(bits:int):uint {\r
-       \r
-                       var res:uint = 0;\r
-                       \r
-                       for (var i : int = 0; i < bits; i++) {\r
-                               if (bitIndex > 7) {\r
-                                       bitIndex = 0;\r
-                                       currentByte = readUnsignedByte();\r
-                               }\r
-                               if((currentByte & (1 << (bitIndex++))) != 0) {\r
-                                       res |= (1 << i);\r
-                               }\r
-                       }\r
-                       \r
-                       return res;\r
-               }       \r
-\r
-               public function readUnsignedHuffmanInt(root:HuffmanNode):uint {\r
-\r
-                       while (!root.hasValue) {\r
-                               if (bitIndex > 7) {\r
-                                       bitIndex = 0;\r
-                                       currentByte = readUnsignedByte();\r
-                               }\r
-                               root = (currentByte & (1 << (bitIndex++))) != 0 ? root._o1 : root._o0;\r
-                       }\r
-                       \r
-                       return root._value;                     \r
-               }\r
-       \r
-       }\r
-       \r
-\r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.util {
+
+       import flash.utils.ByteArray;
+       import flash.utils.Endian;
+       import flash.errors.IllegalOperationError;
+       
+       public class BitByteArray extends ByteArray {
+       
+               private var currentByte:uint;
+               private var bitIndex:int = 8;
+       
+               public function BitByteArray() {
+                       this.endian = Endian.LITTLE_ENDIAN;
+               }
+
+               public function readBit():Boolean {
+                       if (bitIndex > 7) {
+                               bitIndex = 0;
+                               currentByte = readUnsignedByte();
+                       }
+                       return (currentByte & (1 << (bitIndex++))) != 0;
+               }
+               
+               public function readUnsignedBitwiseInt(bits:int):uint {
+       
+                       var res:uint = 0;
+                       
+                       for (var i : int = 0; i < bits; i++) {
+                               if (bitIndex > 7) {
+                                       bitIndex = 0;
+                                       currentByte = readUnsignedByte();
+                               }
+                               if((currentByte & (1 << (bitIndex++))) != 0) {
+                                       res |= (1 << i);
+                               }
+                       }
+                       
+                       return res;
+               }       
+
+               public function readUnsignedHuffmanInt(root:HuffmanNode):uint {
+
+                       while (!root.hasValue) {
+                               if (bitIndex > 7) {
+                                       bitIndex = 0;
+                                       currentByte = readUnsignedByte();
+                               }
+                               root = (currentByte & (1 << (bitIndex++))) != 0 ? root._o1 : root._o0;
+                       }
+                       
+                       return root._value;                     
+               }
+       
+       }
+       
+
 }
\ No newline at end of file
index 14a014d..c8ce3ae 100644 (file)
@@ -1,92 +1,92 @@
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-package org.omtk.util {\r
-\r
-       public class HuffmanNode {\r
-       \r
-               private var _parent:HuffmanNode;\r
-       \r
-               public var _o0:HuffmanNode;\r
-               public var _o1:HuffmanNode;\r
-               \r
-               private var _depth:int;\r
-       \r
-               public var _value:int;\r
-               public var hasValue: Boolean;\r
-               private var _full:Boolean = false;\r
-       \r
-               public function HuffmanNode(parent:HuffmanNode = null, value:int = -1) {\r
-                       _parent = parent;\r
-                       if(_parent != null) {\r
-                               _depth = _parent.depth+1;\r
-                       }\r
-                       _value = value;                 \r
-                       _full = value >= 0;\r
-                       hasValue = value >= 0;\r
-               }\r
-       \r
-               public function setNewValue(depth:int, value:uint):Boolean {\r
-             if (full) {\r
-                return false;\r
-             }\r
-             if (depth == 1) {\r
-                if (_o0 == null) {\r
-                   _o0 = new HuffmanNode(this, value);\r
-                   return true;\r
-                } else if (_o1 == null) {\r
-                   _o1 = new HuffmanNode(this, value);\r
-                   return true;\r
-                } else {\r
-                   return false;\r
-                }\r
-             } else {\r
-                return o0.setNewValue(depth - 1, value)\r
-                       ? true : o1.setNewValue(depth - 1, value);\r
-             }\r
-          }    \r
-       \r
-               public function get value():uint {\r
-                       return _value;\r
-               }\r
-       \r
-               public function get o0():HuffmanNode {\r
-                       if(_o0 == null) {\r
-                               _o0 = new HuffmanNode(this);\r
-                       }\r
-                       return _o0;\r
-               }\r
-\r
-               public function get o1():HuffmanNode {\r
-                       if(_o1 == null) {\r
-                               _o1 = new HuffmanNode(this);\r
-                       }\r
-                       return _o1;\r
-               }\r
-       \r
-               public function get depth():int {\r
-                       return _depth;\r
-               }\r
-               \r
-               public function get full():Boolean {\r
-                       return _full ? true\r
-                       : (_full = (_o0 != null && _o0.full && _o1 != null && _o1.full));\r
-               }\r
-               \r
-       }\r
-       \r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+package org.omtk.util {
+
+       public class HuffmanNode {
+       
+               private var _parent:HuffmanNode;
+       
+               public var _o0:HuffmanNode;
+               public var _o1:HuffmanNode;
+               
+               private var _depth:int;
+       
+               public var _value:int;
+               public var hasValue: Boolean;
+               private var _full:Boolean = false;
+       
+               public function HuffmanNode(parent:HuffmanNode = null, value:int = -1) {
+                       _parent = parent;
+                       if(_parent != null) {
+                               _depth = _parent.depth+1;
+                       }
+                       _value = value;                 
+                       _full = value >= 0;
+                       hasValue = value >= 0;
+               }
+       
+               public function setNewValue(depth:int, value:uint):Boolean {
+             if (full) {
+                return false;
+             }
+             if (depth == 1) {
+                if (_o0 == null) {
+                   _o0 = new HuffmanNode(this, value);
+                   return true;
+                } else if (_o1 == null) {
+                   _o1 = new HuffmanNode(this, value);
+                   return true;
+                } else {
+                   return false;
+                }
+             } else {
+                return o0.setNewValue(depth - 1, value)
+                       ? true : o1.setNewValue(depth - 1, value);
+             }
+          }    
+       
+               public function get value():uint {
+                       return _value;
+               }
+       
+               public function get o0():HuffmanNode {
+                       if(_o0 == null) {
+                               _o0 = new HuffmanNode(this);
+                       }
+                       return _o0;
+               }
+
+               public function get o1():HuffmanNode {
+                       if(_o1 == null) {
+                               _o1 = new HuffmanNode(this);
+                       }
+                       return _o1;
+               }
+       
+               public function get depth():int {
+                       return _depth;
+               }
+               
+               public function get full():Boolean {
+                       return _full ? true
+                       : (_full = (_o0 != null && _o0.full && _o1 != null && _o1.full));
+               }
+               
+       }
+       
 }
\ No newline at end of file
index 949b6bd..8cec996 100644 (file)
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import flash.utils.getTimer;\r
-       import flash.utils.ByteArray;\r
-       import org.omtk.ogg.*;\r
-       import org.omtk.util.BitByteArray;\r
-\r
-       public class AudioPacket {\r
-       \r
-               private var modeNumber:int;\r
-               private var mode:Mode;\r
-               private var mapping:Mapping;\r
-               private var n:int;\r
-               \r
-               private var blockFlag:Boolean;\r
-               private var previousWindowFlag:Boolean;\r
-               private var nextWindowFlag:Boolean;\r
-\r
-               private var windowCenter:int;\r
-               private var leftWindowStart:int;\r
-               private var leftWindowEnd:int;\r
-               private var leftN:int;\r
-               private var rightWindowStart:int;\r
-               private var rightWindowEnd:int;\r
-               private var rightN:int;\r
-               \r
-               private var window:Vector.<Number>;\r
-               private var freq0:Vector.<Number>;\r
-               private var freq1:Vector.<Number>;\r
-               private var pcm0:Vector.<Number>;\r
-               private var pcm1:Vector.<Number>;\r
-               \r
-               private var channelFloors:Vector.<Floor>;\r
-               private var noResidues:Vector.<Boolean>;                \r
-\r
-               private var _lastPacket: Boolean;\r
-               private var _lastGranulePosition: int;\r
-\r
-               public function AudioPacket(vorbis:VorbisStream, packet: OggPacket, currentGranulePosition: int) {\r
-               \r
-                       var source: BitByteArray = packet.data;\r
-                       _lastPacket = packet.lastPacket;\r
-                       _lastGranulePosition = packet.lastGranulePosition;\r
-                       \r
-                       var i:int;\r
-                       var j:int;\r
-                       var k:int;\r
-       \r
-                       var sHeader:SetupHeader = vorbis.setupHeader;\r
-                       var iHeader:IdentificationHeader = vorbis.identificationHeader;\r
-                       var modes:Vector.<Mode> = sHeader.modes;\r
-                       var mappings:Vector.<Mapping> = sHeader.mappings;\r
-                       var residues:Vector.<Residue> = sHeader.residues;\r
-                       var channels:int = iHeader.channels;\r
-       \r
-                       if (source.readUnsignedBitwiseInt(1) != 0) {\r
-                               throw new Error("Packet type mismatch when trying to create an audio packet.");\r
-                       }\r
-       \r
-                       modeNumber = source.readUnsignedBitwiseInt(Util.ilog(modes.length - 1));\r
-       \r
-                       mode = modes[modeNumber];\r
-                       \r
-                       if(mode == null) {\r
-                               throw new Error("Reference to invalid mode in audio packet.");\r
-                       }\r
-       \r
-                       mapping = mappings[mode.mapping];\r
-       \r
-                       var magnitudes:Vector.<int> = mapping.magnitudes;\r
-                       var angles:Vector.<int> = mapping.angles;\r
-       \r
-                       blockFlag = mode.blockFlag;\r
-       \r
-                       var blockSize0:int = iHeader.blockSize0;\r
-                       var blockSize1:int = iHeader.blockSize1;\r
-       \r
-                       n = blockFlag ? blockSize1 : blockSize0;\r
-       \r
-                       if (blockFlag) {\r
-                               previousWindowFlag = source.readBit();\r
-                               nextWindowFlag = source.readBit();\r
-                       }\r
-       \r
-                       windowCenter = n / 2;\r
-       \r
-                       if (blockFlag && !previousWindowFlag) {\r
-                               leftWindowStart = n / 4 - blockSize0 / 4;\r
-                               leftWindowEnd = n / 4 + blockSize0 / 4;\r
-                               leftN = blockSize0 / 2;\r
-                       } else {\r
-                               leftWindowStart = 0;\r
-                               leftWindowEnd = n / 2;\r
-                               leftN = windowCenter;\r
-                       }\r
-       \r
-                       if (blockFlag && !nextWindowFlag) {\r
-                               rightWindowStart = n * 3 / 4 - blockSize0 / 4;\r
-                               rightWindowEnd = n * 3 / 4 + blockSize0 / 4;\r
-                               rightN = blockSize0 / 2;\r
-                       } else {\r
-                               rightWindowStart = windowCenter;\r
-                               rightWindowEnd = n;\r
-                               rightN = n / 2;\r
-                       }\r
-       \r
-                       window = getComputedWindow(vorbis);\r
-       \r
-                       channelFloors = new Vector.<Floor>(channels, true);\r
-                       noResidues = new Vector.<Boolean>(channels, true);\r
-       \r
-                       freq0 = new Vector.<Number>(n, true);\r
-                       freq1 = new Vector.<Number>(n, true);\r
-                       pcm0 = new Vector.<Number>(n, true);\r
-                       pcm1 = new Vector.<Number>(n, true);\r
-\r
-                       var allFloorsEmpty: Boolean = true;\r
-                       var submapNumber: int;\r
-                       var floorNumber: int;\r
-                       var decodedFloor: Floor;\r
-       \r
-                       for(i = 0; i < channels; i++) {\r
-                               submapNumber = mapping.mux[i];\r
-                               floorNumber = mapping.submapFloors[submapNumber];\r
-                               decodedFloor = sHeader.floors[floorNumber].decodeFloor(vorbis, source);\r
-                               channelFloors[i] = decodedFloor;\r
-                               noResidues[i] = decodedFloor == null;\r
-                               if (decodedFloor != null) {\r
-                                       allFloorsEmpty = false;\r
-                               }\r
-                       }\r
-       \r
-                       if(allFloorsEmpty) {\r
-                               return;\r
-                       }\r
-                       \r
-                       var mag: int;\r
-                       var ang: int;\r
-\r
-                       for(i = 0; i < magnitudes.length; i++) {\r
-                               mag = magnitudes[i];\r
-                               ang = angles[i];\r
-                               if (!noResidues[mag] || !noResidues[ang]) {\r
-                                       noResidues[mag] = false;\r
-                                       noResidues[ang] = false;\r
-                               }\r
-                       }\r
-       \r
-                       var ch: int;\r
-                       var doNotDecodeFlags: Vector.<Boolean>;\r
-                       var residue:Residue;\r
-                       \r
-                       for(i = 0; i < mapping.submaps; i++) {\r
-                       \r
-                               doNotDecodeFlags = new Vector.<Boolean>();\r
-                               \r
-                               for(j = 0; j < channels; j++) {\r
-                                       if(mapping.mux[j] == i) {\r
-                                               doNotDecodeFlags.push(noResidues[j]);\r
-                                       }\r
-                               }\r
-\r
-                               residue = residues[mapping.submapResidues[i]];\r
-                               \r
-                               residue.decodeResidue(vorbis, source, mode, ch, doNotDecodeFlags, freq0, freq1);\r
-                       }\r
-\r
-                       var a: Number;\r
-                       var m: Number;\r
-       \r
-                       for(i = mapping.couplingSteps - 1; i >= 0; i--) {\r
-                       \r
-                               mag = magnitudes[i];\r
-                               ang = angles[i];\r
-                               \r
-                               for (j = 0; j < freq0.length; j++) {\r
-                                       \r
-                                       a = ang == 0 ? freq0[j] : freq1[j];\r
-                                       m = mag == 0 ? freq0[j] : freq1[j];\r
-                                       \r
-                                       if(a > 0) {\r
-                                               if(ang == 0) {\r
-                                                       freq0[j] = m > 0 ? m - a : m + a;\r
-                                               }\r
-                                               else {\r
-                                                       freq1[j] = m > 0 ? m - a : m + a;\r
-                                               }\r
-                                       }\r
-                                       else {\r
-                                               if(mag == 0) {\r
-                                                       freq0[j] = m > 0 ? m + a : m - a;\r
-                                               }\r
-                                               else {\r
-                                                       freq1[j] = m > 0 ? m + a : m - a;\r
-                                               }\r
-                                               \r
-                                               if(ang == 0) {\r
-                                                       freq0[j] = m;\r
-                                               }\r
-                                               else {\r
-                                                       freq1[j] = m;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-                       \r
-                       if(channelFloors[0] != null) {\r
-                               Floor(channelFloors[0]).computeFloor(freq0);\r
-                       }\r
-                       \r
-                       if(channelFloors[1] != null) {\r
-                               Floor(channelFloors[1]).computeFloor(freq1);\r
-                       }\r
-\r
-                       // perform an inverse mdct to all channels\r
-                       var mdct: Mdct = blockFlag ? iHeader.mdct1 : iHeader.mdct0;\r
-                       mdct.imdct(freq0, window, pcm0);\r
-                       mdct.imdct(freq1, window, pcm1);\r
-\r
-                       if(_lastPacket) {\r
-                               if(leftWindowEnd - leftWindowStart > _lastGranulePosition - currentGranulePosition) {\r
-                                       leftWindowEnd = leftWindowStart + _lastGranulePosition - currentGranulePosition\r
-                               }\r
-                               if(rightWindowStart - leftWindowStart > _lastGranulePosition - currentGranulePosition) {\r
-                                       rightWindowStart = leftWindowStart + _lastGranulePosition - currentGranulePosition\r
-                               }\r
-                       }\r
-\r
-               }       \r
-       \r
-               private function getComputedWindow(vorbis:VorbisStream):Vector.<Number> {\r
-                       \r
-                       var i:int;\r
-                       \r
-                       var ix:int = (blockFlag ? 4 : 0) + (previousWindowFlag ? 2 : 0) + (nextWindowFlag ? 1 : 0);\r
-                       var w:Vector.<Number> = vorbis.windows[ix];\r
-                       \r
-                       var x:Number;\r
-                       \r
-                       if (w == null) {\r
-                               w = new Vector.<Number>(n);\r
-       \r
-                               for(i = 0; i < leftWindowStart; i++) {\r
-                                       w[i] = 0;\r
-                               }\r
-       \r
-                               for (i = 0; i < leftN; i++) {\r
-                                       x = (i + .5) / leftN * Math.PI / 2.;\r
-                                       x = Math.sin(x);\r
-                                       x *= x;\r
-                                       x *= Math.PI / 2.;\r
-                                       x = Math.sin(x);\r
-                                       w[i + leftWindowStart] = x;\r
-                               }\r
-       \r
-                               for (i = leftWindowEnd; i < rightWindowStart; i++) {\r
-                                       w[i] = 1;\r
-                               }\r
-       \r
-                               for (i = 0; i < rightN; i++) {\r
-                                       x = (rightN - i - .5) / rightN * Math.PI / 2.;\r
-                                       x = Math.sin(x);\r
-                                       x *= x;\r
-                                       x *= Math.PI / 2.;\r
-                                       x = Math.sin(x);\r
-                                       w[i + rightWindowStart] = x;\r
-                               }\r
-       \r
-                               for(i = rightN + rightWindowStart; i < n; i++) {\r
-                                       w[i] = 0;\r
-                               }\r
-\r
-                               for(i = 0; i < w.length; i++) {\r
-                                       w[i] *= 0.5;\r
-                               }\r
-       \r
-                               vorbis.windows[ix] = w;\r
-                       }\r
-                       \r
-                       return w;\r
-               }       \r
-               \r
-               \r
-               public function readPcm(previousPacket:AudioPacket, target: ByteArray): int {\r
-               \r
-                       var j:int;\r
-                       var j2:int;\r
-                       var ppcm0:Vector.<Number> = previousPacket.pcm0;\r
-                       var ppcm1:Vector.<Number> = previousPacket.pcm1;\r
-                       \r
-                       j2 = previousPacket.rightWindowStart;\r
-                       \r
-                       for(j = leftWindowStart; j < leftWindowEnd; j++) {\r
-                               target.writeFloat(pcm0[j] + ppcm0[j2]);\r
-                               target.writeFloat(pcm1[j] + ppcm1[j2++]);\r
-                       }\r
-\r
-                       for (j = leftWindowEnd; j < rightWindowStart; j++) {\r
-                               target.writeFloat(pcm0[j]);\r
-                               target.writeFloat(pcm1[j]);\r
-                       }\r
-\r
-                       return numberOfSamples;\r
-\r
-               }\r
-\r
-               public function get numberOfSamples():int {\r
-                       return rightWindowStart - leftWindowStart;\r
-               }\r
-\r
-               public function get lastPacket(): Boolean {\r
-                       return lastPacket;\r
-               }\r
-               \r
-               public function get lastGranulePosition(): int {\r
-                       return lastGranulePosition;\r
-               }\r
-       \r
-       }\r
-\r
-\r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import flash.utils.getTimer;
+       import flash.utils.ByteArray;
+       import org.omtk.ogg.*;
+       import org.omtk.util.BitByteArray;
+
+       public class AudioPacket {
+       
+               private var modeNumber:int;
+               private var mode:Mode;
+               private var mapping:Mapping;
+               private var n:int;
+               
+               private var blockFlag:Boolean;
+               private var previousWindowFlag:Boolean;
+               private var nextWindowFlag:Boolean;
+
+               private var windowCenter:int;
+               private var leftWindowStart:int;
+               private var leftWindowEnd:int;
+               private var leftN:int;
+               private var rightWindowStart:int;
+               private var rightWindowEnd:int;
+               private var rightN:int;
+               
+               private var window:Vector.<Number>;
+               private var freq0:Vector.<Number>;
+               private var freq1:Vector.<Number>;
+               private var pcm0:Vector.<Number>;
+               private var pcm1:Vector.<Number>;
+               
+               private var channelFloors:Vector.<Floor>;
+               private var noResidues:Vector.<Boolean>;                
+
+               private var _lastPacket: Boolean;
+               private var _lastGranulePosition: int;
+
+               public function AudioPacket(vorbis:VorbisStream, packet: OggPacket, currentGranulePosition: int) {
+               
+                       var source: BitByteArray = packet.data;
+                       _lastPacket = packet.lastPacket;
+                       _lastGranulePosition = packet.lastGranulePosition;
+                       
+                       var i:int;
+                       var j:int;
+                       var k:int;
+       
+                       var sHeader:SetupHeader = vorbis.setupHeader;
+                       var iHeader:IdentificationHeader = vorbis.identificationHeader;
+                       var modes:Vector.<Mode> = sHeader.modes;
+                       var mappings:Vector.<Mapping> = sHeader.mappings;
+                       var residues:Vector.<Residue> = sHeader.residues;
+                       var channels:int = iHeader.channels;
+       
+                       if (source.readUnsignedBitwiseInt(1) != 0) {
+                               throw new Error("Packet type mismatch when trying to create an audio packet.");
+                       }
+       
+                       modeNumber = source.readUnsignedBitwiseInt(Util.ilog(modes.length - 1));
+       
+                       mode = modes[modeNumber];
+                       
+                       if(mode == null) {
+                               throw new Error("Reference to invalid mode in audio packet.");
+                       }
+       
+                       mapping = mappings[mode.mapping];
+       
+                       var magnitudes:Vector.<int> = mapping.magnitudes;
+                       var angles:Vector.<int> = mapping.angles;
+       
+                       blockFlag = mode.blockFlag;
+       
+                       var blockSize0:int = iHeader.blockSize0;
+                       var blockSize1:int = iHeader.blockSize1;
+       
+                       n = blockFlag ? blockSize1 : blockSize0;
+       
+                       if (blockFlag) {
+                               previousWindowFlag = source.readBit();
+                               nextWindowFlag = source.readBit();
+                       }
+       
+                       windowCenter = n / 2;
+       
+                       if (blockFlag && !previousWindowFlag) {
+                               leftWindowStart = n / 4 - blockSize0 / 4;
+                               leftWindowEnd = n / 4 + blockSize0 / 4;
+                               leftN = blockSize0 / 2;
+                       } else {
+                               leftWindowStart = 0;
+                               leftWindowEnd = n / 2;
+                               leftN = windowCenter;
+                       }
+       
+                       if (blockFlag && !nextWindowFlag) {
+                               rightWindowStart = n * 3 / 4 - blockSize0 / 4;
+                               rightWindowEnd = n * 3 / 4 + blockSize0 / 4;
+                               rightN = blockSize0 / 2;
+                       } else {
+                               rightWindowStart = windowCenter;
+                               rightWindowEnd = n;
+                               rightN = n / 2;
+                       }
+       
+                       window = getComputedWindow(vorbis);
+       
+                       channelFloors = new Vector.<Floor>(channels, true);
+                       noResidues = new Vector.<Boolean>(channels, true);
+       
+                       freq0 = new Vector.<Number>(n, true);
+                       freq1 = new Vector.<Number>(n, true);
+                       pcm0 = new Vector.<Number>(n, true);
+                       pcm1 = new Vector.<Number>(n, true);
+
+                       var allFloorsEmpty: Boolean = true;
+                       var submapNumber: int;
+                       var floorNumber: int;
+                       var decodedFloor: Floor;
+       
+                       for(i = 0; i < channels; i++) {
+                               submapNumber = mapping.mux[i];
+                               floorNumber = mapping.submapFloors[submapNumber];
+                               decodedFloor = sHeader.floors[floorNumber].decodeFloor(vorbis, source);
+                               channelFloors[i] = decodedFloor;
+                               noResidues[i] = decodedFloor == null;
+                               if (decodedFloor != null) {
+                                       allFloorsEmpty = false;
+                               }
+                       }
+       
+                       if(allFloorsEmpty) {
+                               return;
+                       }
+                       
+                       var mag: int;
+                       var ang: int;
+
+                       for(i = 0; i < magnitudes.length; i++) {
+                               mag = magnitudes[i];
+                               ang = angles[i];
+                               if (!noResidues[mag] || !noResidues[ang]) {
+                                       noResidues[mag] = false;
+                                       noResidues[ang] = false;
+                               }
+                       }
+       
+                       var ch: int;
+                       var doNotDecodeFlags: Vector.<Boolean>;
+                       var residue:Residue;
+                       
+                       for(i = 0; i < mapping.submaps; i++) {
+                       
+                               doNotDecodeFlags = new Vector.<Boolean>();
+                               
+                               for(j = 0; j < channels; j++) {
+                                       if(mapping.mux[j] == i) {
+                                               doNotDecodeFlags.push(noResidues[j]);
+                                       }
+                               }
+
+                               residue = residues[mapping.submapResidues[i]];
+                               
+                               residue.decodeResidue(vorbis, source, mode, ch, doNotDecodeFlags, freq0, freq1);
+                       }
+
+                       var a: Number;
+                       var m: Number;
+       
+                       for(i = mapping.couplingSteps - 1; i >= 0; i--) {
+                       
+                               mag = magnitudes[i];
+                               ang = angles[i];
+                               
+                               for (j = 0; j < freq0.length; j++) {
+                                       
+                                       a = ang == 0 ? freq0[j] : freq1[j];
+                                       m = mag == 0 ? freq0[j] : freq1[j];
+                                       
+                                       if(a > 0) {
+                                               if(ang == 0) {
+                                                       freq0[j] = m > 0 ? m - a : m + a;
+                                               }
+                                               else {
+                                                       freq1[j] = m > 0 ? m - a : m + a;
+                                               }
+                                       }
+                                       else {
+                                               if(mag == 0) {
+                                                       freq0[j] = m > 0 ? m + a : m - a;
+                                               }
+                                               else {
+                                                       freq1[j] = m > 0 ? m + a : m - a;
+                                               }
+                                               
+                                               if(ang == 0) {
+                                                       freq0[j] = m;
+                                               }
+                                               else {
+                                                       freq1[j] = m;
+                                               }
+                                       }
+                               }
+                       }
+                       
+                       if(channelFloors[0] != null) {
+                               Floor(channelFloors[0]).computeFloor(freq0);
+                       }
+                       
+                       if(channelFloors[1] != null) {
+                               Floor(channelFloors[1]).computeFloor(freq1);
+                       }
+
+                       // perform an inverse mdct to all channels
+                       var mdct: Mdct = blockFlag ? iHeader.mdct1 : iHeader.mdct0;
+                       mdct.imdct(freq0, window, pcm0);
+                       mdct.imdct(freq1, window, pcm1);
+
+                       if(_lastPacket) {
+                               if(leftWindowEnd - leftWindowStart > _lastGranulePosition - currentGranulePosition) {
+                                       leftWindowEnd = leftWindowStart + _lastGranulePosition - currentGranulePosition
+                               }
+                               if(rightWindowStart - leftWindowStart > _lastGranulePosition - currentGranulePosition) {
+                                       rightWindowStart = leftWindowStart + _lastGranulePosition - currentGranulePosition
+                               }
+                       }
+
+               }       
+       
+               private function getComputedWindow(vorbis:VorbisStream):Vector.<Number> {
+                       
+                       var i:int;
+                       
+                       var ix:int = (blockFlag ? 4 : 0) + (previousWindowFlag ? 2 : 0) + (nextWindowFlag ? 1 : 0);
+                       var w:Vector.<Number> = vorbis.windows[ix];
+                       
+                       var x:Number;
+                       
+                       if (w == null) {
+                               w = new Vector.<Number>(n);
+       
+                               for(i = 0; i < leftWindowStart; i++) {
+                                       w[i] = 0;
+                               }
+       
+                               for (i = 0; i < leftN; i++) {
+                                       x = (i + .5) / leftN * Math.PI / 2.;
+                                       x = Math.sin(x);
+                                       x *= x;
+                                       x *= Math.PI / 2.;
+                                       x = Math.sin(x);
+                                       w[i + leftWindowStart] = x;
+                               }
+       
+                               for (i = leftWindowEnd; i < rightWindowStart; i++) {
+                                       w[i] = 1;
+                               }
+       
+                               for (i = 0; i < rightN; i++) {
+                                       x = (rightN - i - .5) / rightN * Math.PI / 2.;
+                                       x = Math.sin(x);
+                                       x *= x;
+                                       x *= Math.PI / 2.;
+                                       x = Math.sin(x);
+                                       w[i + rightWindowStart] = x;
+                               }
+       
+                               for(i = rightN + rightWindowStart; i < n; i++) {
+                                       w[i] = 0;
+                               }
+
+                               for(i = 0; i < w.length; i++) {
+                                       w[i] *= 0.5;
+                               }
+       
+                               vorbis.windows[ix] = w;
+                       }
+                       
+                       return w;
+               }       
+               
+               
+               public function readPcm(previousPacket:AudioPacket, target: ByteArray): int {
+               
+                       var j:int;
+                       var j2:int;
+                       var ppcm0:Vector.<Number> = previousPacket.pcm0;
+                       var ppcm1:Vector.<Number> = previousPacket.pcm1;
+                       
+                       j2 = previousPacket.rightWindowStart;
+                       
+                       for(j = leftWindowStart; j < leftWindowEnd; j++) {
+                               target.writeFloat(pcm0[j] + ppcm0[j2]);
+                               target.writeFloat(pcm1[j] + ppcm1[j2++]);
+                       }
+
+                       for (j = leftWindowEnd; j < rightWindowStart; j++) {
+                               target.writeFloat(pcm0[j]);
+                               target.writeFloat(pcm1[j]);
+                       }
+
+                       return numberOfSamples;
+
+               }
+
+               public function get numberOfSamples():int {
+                       return rightWindowStart - leftWindowStart;
+               }
+
+               public function get lastPacket(): Boolean {
+                       return lastPacket;
+               }
+               
+               public function get lastGranulePosition(): int {
+                       return lastGranulePosition;
+               }
+       
+       }
+
+
 }
\ No newline at end of file
index 27137aa..ed84041 100644 (file)
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import flash.errors.IllegalOperationError;\r
-       import org.omtk.util.*;\r
-\r
-       public class CodeBook {\r
-\r
-               private var entries:uint;\r
-               private var entryLengths:Vector.<int>;\r
-               private var valueVector:Vector.<Vector.<Number>>;\r
-\r
-               private var codeBookLookupType:int = -1;\r
-\r
-               public var huffmanRoot:HuffmanNode;\r
-               public var dimensions:uint;\r
-\r
-               public function CodeBook( source: BitByteArray ) {\r
-\r
-                       var i:int;\r
-                       var j:int;\r
-               \r
-                       var syncPattern:uint = source.readUnsignedBitwiseInt(24);\r
-                       if(syncPattern !=0x564342) {\r
-                               throw new IllegalOperationError("Illegal codebook sync pattern: "+syncPattern);\r
-                       }\r
-               \r
-                       dimensions = source.readUnsignedBitwiseInt(16);\r
-                       entries = source.readUnsignedBitwiseInt(24);\r
-                       \r
-                       entryLengths = new Vector.<int>(entries);\r
-                       \r
-                       var ordered:Boolean = source.readBit();\r
-                       \r
-                       if(ordered) {\r
-                               var cl:int = source.readUnsignedBitwiseInt(5)+1;\r
-                               for(i=0; i<entryLengths.length; ) {\r
-                                       var num:int = source.readUnsignedBitwiseInt(Util.ilog(entryLengths.length-i));\r
-                                       if(i+num>entryLengths.length) {\r
-                                               throw new Error("The codebook entry length list is longer than the actual number of entry lengths.");\r
-                                       }\r
-                                       for(j=i; j<i+num; j++) {\r
-                                               entryLengths[j] = cl;\r
-                                       }\r
-                                       //Arrays.fill(entryLengths, i, i+num, cl);\r
-                                       cl++;\r
-                                       i+=num;\r
-                               }\r
-                       }\r
-                       else {\r
-                               // !ordered\r
-                               var sparse:Boolean = source.readBit();\r
-                               \r
-                               if(sparse) {\r
-                                       for(i=0; i<entryLengths.length; i++) {\r
-                                               if(source.readBit()) {\r
-                                                       entryLengths[i]=source.readUnsignedBitwiseInt(5)+1;\r
-                                               }\r
-                                               else {\r
-                                                       entryLengths[i]=-1;\r
-                                               }\r
-                                       }\r
-                               }\r
-                               else {\r
-                                       // !sparse\r
-                                       //Alert.show("entryLengths.length: "+entryLengths.length, "CodeBook");\r
-                                       for(i=0; i<entryLengths.length; i++) {\r
-                                               entryLengths[i]=source.readUnsignedBitwiseInt(5)+1;\r
-                                       }\r
-                               }\r
-                       \r
-                       }\r
-                       \r
-                       if (!createHuffmanTree(entryLengths)) {\r
-                               throw new Error("An exception was thrown when building the codebook Huffman tree.");\r
-                       }       \r
-\r
-                       codeBookLookupType = source.readUnsignedBitwiseInt(4);\r
-\r
-                       switch(codeBookLookupType) {\r
-                       case 0:\r
-                               // codebook has no scalar vectors to be calculated\r
-                               break;\r
-                       case 1:\r
-                       case 2:\r
-                               var codeBookMinimumValue:Number = Util.float32unpack(source.readUnsignedBitwiseInt(32));\r
-                               var codeBookDeltaValue:Number = Util.float32unpack(source.readUnsignedBitwiseInt(32));\r
-\r
-                               var codeBookValueBits:uint = source.readUnsignedBitwiseInt(4)+1;\r
-                               var codeBookSequenceP:Boolean = source.readBit();\r
-\r
-                               var codeBookLookupValues:uint = 0;\r
-\r
-                               if(codeBookLookupType==1) {\r
-                                       codeBookLookupValues=Util.lookup1Values(entries, dimensions);\r
-                               }\r
-                               else {\r
-                                       codeBookLookupValues=entries*dimensions;\r
-                               }\r
-\r
-                               var codeBookMultiplicands:Vector.<int> = new Vector.<int>(codeBookLookupValues);\r
-\r
-                               for(i=0; i < codeBookMultiplicands.length; i++) {\r
-                                       codeBookMultiplicands[i]=source.readUnsignedBitwiseInt(codeBookValueBits);\r
-                               }\r
-\r
-                               valueVector = new Vector.<Vector.<Number>>(entries);\r
-\r
-                               if(codeBookLookupType==1) {\r
-                                       for(i=0; i<entries; i++) {\r
-                                               valueVector[i] = new Vector.<Number>(dimensions);\r
-                                               var last:Number = 0.0;\r
-                                               var indexDivisor:uint = 1;\r
-                                               for(j=0; j<dimensions; j++) {\r
-                                                       var multiplicandOffset:int = (i/indexDivisor)%codeBookLookupValues;\r
-                                                       valueVector[i][j]=\r
-                                                               codeBookMultiplicands[multiplicandOffset]*codeBookDeltaValue+codeBookMinimumValue+last;\r
-                                                       if(codeBookSequenceP) {\r
-                                                               last = valueVector[i][j];\r
-                                                       }\r
-                                                       indexDivisor*=codeBookLookupValues;\r
-                                               }\r
-                                       }\r
-                               }\r
-                               else {\r
-                                       throw new Error("Unsupported codebook lookup type: "+codeBookLookupType);\r
-                                       /** @todo implement */\r
-                               }\r
-                               break;\r
-                       default:\r
-                               throw new Error("Unsupported codebook lookup type: "+codeBookLookupType);\r
-                       }\r
-               }\r
-       \r
-               private function createHuffmanTree(entryLengths:Vector.<int>):Boolean {\r
-               \r
-                       var i:int;\r
-               \r
-                       huffmanRoot = new HuffmanNode();\r
-                       for(i=0; i<entryLengths.length; i++) {\r
-                               var el:int = entryLengths[i];\r
-                               if(el>0) {\r
-                                       if(!huffmanRoot.setNewValue(el, i)) {\r
-                                               return false;\r
-                                       }\r
-                               }\r
-                       }\r
-                       return true;\r
-               }\r
-\r
-\r
-               public function readVvAdd(a0:Vector.<Number>, a1:Vector.<Number>, left:Boolean, right:Boolean, source:BitByteArray, offset:int, length:int):void {\r
-       \r
-                       var i:int;\r
-                       var j:int;\r
-       \r
-                       if (!left && !right) {\r
-                               return;\r
-                       }\r
-\r
-                       // 1 or 2 channels      \r
-                       var ch:int = \r
-                               left && right ? 2 : 1;\r
-\r
-                       var lim:int;\r
-                       var ix:int;\r
-                       var ve:Vector.<Number>;\r
-                       \r
-                       if(left && right) {\r
-                               lim = (offset + length) / 2;\r
-                               var chptr:int = 0;\r
-                               for (i = offset / 2; i < lim;) {\r
-                                       ix = source.readUnsignedHuffmanInt(huffmanRoot);\r
-                                       ve = valueVector[ix];\r
-                                       for (j = 0; j < dimensions; j++) {\r
-                                               if(chptr == 0) {\r
-                                                       a0[i] += ve[j];\r
-                                               }\r
-                                               else {\r
-                                                       a1[i] += ve[j];\r
-                                               }\r
-                                               chptr++;\r
-                                               if(chptr == 2) {\r
-                                                       chptr = 0;\r
-                                                       i++;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-                       else {\r
-                               var a : Vector.<Number> = left ? a0 : a1;\r
-                               lim = offset + length;\r
-                               for (i = offset; i < lim;) {\r
-                                       ve = valueVector[source.readUnsignedHuffmanInt(huffmanRoot)];\r
-                                       for (j = 0; j < dimensions; j++) {\r
-                                               a[i] += ve[j];\r
-                                               i++;\r
-                                       }\r
-                               }\r
-                       }\r
-\r
-               }\r
-               \r
-       }\r
-       \r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import flash.errors.IllegalOperationError;
+       import org.omtk.util.*;
+
+       public class CodeBook {
+
+               private var entries:uint;
+               private var entryLengths:Vector.<int>;
+               private var valueVector:Vector.<Vector.<Number>>;
+
+               private var codeBookLookupType:int = -1;
+
+               public var huffmanRoot:HuffmanNode;
+               public var dimensions:uint;
+
+               public function CodeBook( source: BitByteArray ) {
+
+                       var i:int;
+                       var j:int;
+               
+                       var syncPattern:uint = source.readUnsignedBitwiseInt(24);
+                       if(syncPattern !=0x564342) {
+                               throw new IllegalOperationError("Illegal codebook sync pattern: "+syncPattern);
+                       }
+               
+                       dimensions = source.readUnsignedBitwiseInt(16);
+                       entries = source.readUnsignedBitwiseInt(24);
+                       
+                       entryLengths = new Vector.<int>(entries);
+                       
+                       var ordered:Boolean = source.readBit();
+                       
+                       if(ordered) {
+                               var cl:int = source.readUnsignedBitwiseInt(5)+1;
+                               for(i=0; i<entryLengths.length; ) {
+                                       var num:int = source.readUnsignedBitwiseInt(Util.ilog(entryLengths.length-i));
+                                       if(i+num>entryLengths.length) {
+                                               throw new Error("The codebook entry length list is longer than the actual number of entry lengths.");
+                                       }
+                                       for(j=i; j<i+num; j++) {
+                                               entryLengths[j] = cl;
+                                       }
+                                       //Arrays.fill(entryLengths, i, i+num, cl);
+                                       cl++;
+                                       i+=num;
+                               }
+                       }
+                       else {
+                               // !ordered
+                               var sparse:Boolean = source.readBit();
+                               
+                               if(sparse) {
+                                       for(i=0; i<entryLengths.length; i++) {
+                                               if(source.readBit()) {
+                                                       entryLengths[i]=source.readUnsignedBitwiseInt(5)+1;
+                                               }
+                                               else {
+                                                       entryLengths[i]=-1;
+                                               }
+                                       }
+                               }
+                               else {
+                                       // !sparse
+                                       //Alert.show("entryLengths.length: "+entryLengths.length, "CodeBook");
+                                       for(i=0; i<entryLengths.length; i++) {
+                                               entryLengths[i]=source.readUnsignedBitwiseInt(5)+1;
+                                       }
+                               }
+                       
+                       }
+                       
+                       if (!createHuffmanTree(entryLengths)) {
+                               throw new Error("An exception was thrown when building the codebook Huffman tree.");
+                       }       
+
+                       codeBookLookupType = source.readUnsignedBitwiseInt(4);
+
+                       switch(codeBookLookupType) {
+                       case 0:
+                               // codebook has no scalar vectors to be calculated
+                               break;
+                       case 1:
+                       case 2:
+                               var codeBookMinimumValue:Number = Util.float32unpack(source.readUnsignedBitwiseInt(32));
+                               var codeBookDeltaValue:Number = Util.float32unpack(source.readUnsignedBitwiseInt(32));
+
+                               var codeBookValueBits:uint = source.readUnsignedBitwiseInt(4)+1;
+                               var codeBookSequenceP:Boolean = source.readBit();
+
+                               var codeBookLookupValues:uint = 0;
+
+                               if(codeBookLookupType==1) {
+                                       codeBookLookupValues=Util.lookup1Values(entries, dimensions);
+                               }
+                               else {
+                                       codeBookLookupValues=entries*dimensions;
+                               }
+
+                               var codeBookMultiplicands:Vector.<int> = new Vector.<int>(codeBookLookupValues);
+
+                               for(i=0; i < codeBookMultiplicands.length; i++) {
+                                       codeBookMultiplicands[i]=source.readUnsignedBitwiseInt(codeBookValueBits);
+                               }
+
+                               valueVector = new Vector.<Vector.<Number>>(entries);
+
+                               if(codeBookLookupType==1) {
+                                       for(i=0; i<entries; i++) {
+                                               valueVector[i] = new Vector.<Number>(dimensions);
+                                               var last:Number = 0.0;
+                                               var indexDivisor:uint = 1;
+                                               for(j=0; j<dimensions; j++) {
+                                                       var multiplicandOffset:int = (i/indexDivisor)%codeBookLookupValues;
+                                                       valueVector[i][j]=
+                                                               codeBookMultiplicands[multiplicandOffset]*codeBookDeltaValue+codeBookMinimumValue+last;
+                                                       if(codeBookSequenceP) {
+                                                               last = valueVector[i][j];
+                                                       }
+                                                       indexDivisor*=codeBookLookupValues;
+                                               }
+                                       }
+                               }
+                               else {
+                                       throw new Error("Unsupported codebook lookup type: "+codeBookLookupType);
+                                       /** @todo implement */
+                               }
+                               break;
+                       default:
+                               throw new Error("Unsupported codebook lookup type: "+codeBookLookupType);
+                       }
+               }
+       
+               private function createHuffmanTree(entryLengths:Vector.<int>):Boolean {
+               
+                       var i:int;
+               
+                       huffmanRoot = new HuffmanNode();
+                       for(i=0; i<entryLengths.length; i++) {
+                               var el:int = entryLengths[i];
+                               if(el>0) {
+                                       if(!huffmanRoot.setNewValue(el, i)) {
+                                               return false;
+                                       }
+                               }
+                       }
+                       return true;
+               }
+
+
+               public function readVvAdd(a0:Vector.<Number>, a1:Vector.<Number>, left:Boolean, right:Boolean, source:BitByteArray, offset:int, length:int):void {
+       
+                       var i:int;
+                       var j:int;
+       
+                       if (!left && !right) {
+                               return;
+                       }
+
+                       // 1 or 2 channels      
+                       var ch:int = 
+                               left && right ? 2 : 1;
+
+                       var lim:int;
+                       var ix:int;
+                       var ve:Vector.<Number>;
+                       
+                       if(left && right) {
+                               lim = (offset + length) / 2;
+                               var chptr:int = 0;
+                               for (i = offset / 2; i < lim;) {
+                                       ix = source.readUnsignedHuffmanInt(huffmanRoot);
+                                       ve = valueVector[ix];
+                                       for (j = 0; j < dimensions; j++) {
+                                               if(chptr == 0) {
+                                                       a0[i] += ve[j];
+                                               }
+                                               else {
+                                                       a1[i] += ve[j];
+                                               }
+                                               chptr++;
+                                               if(chptr == 2) {
+                                                       chptr = 0;
+                                                       i++;
+                                               }
+                                       }
+                               }
+                       }
+                       else {
+                               var a : Vector.<Number> = left ? a0 : a1;
+                               lim = offset + length;
+                               for (i = offset; i < lim;) {
+                                       ve = valueVector[source.readUnsignedHuffmanInt(huffmanRoot)];
+                                       for (j = 0; j < dimensions; j++) {
+                                               a[i] += ve[j];
+                                               i++;
+                                       }
+                               }
+                       }
+
+               }
+               
+       }
+       
 }
\ No newline at end of file
index 81885a6..6cf3bfd 100644 (file)
@@ -1,81 +1,81 @@
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import flash.utils.ByteArray;\r
-       import flash.utils.Endian;\r
-       import flash.utils.Dictionary;\r
-       import org.omtk.ogg.*;\r
-\r
-       public class CommentHeader {\r
-       \r
-               private var _vendor:String;\r
-               private var _comments:Dictionary = new Dictionary();\r
-       \r
-               public function CommentHeader(source:ByteArray)\r
-               {\r
-                       init( source );\r
-               }\r
-               \r
-               private function init( source: ByteArray ): void\r
-               {\r
-                       source.readByte();\r
-                       source.readByte();\r
-                       source.readByte();\r
-                       source.readByte();\r
-                       source.readByte();\r
-                       source.readByte();\r
-\r
-                       _vendor = readUtf8String(source);\r
-                       \r
-                       var ucLength:int = source.readUnsignedInt();\r
-                       \r
-                       for(var i:int = 0; i < ucLength; i++) {\r
-                               var comment:String = readUtf8String(source);\r
-                               var ix:int = comment.indexOf('=');\r
-                               var key:String = comment.substring(0, ix);\r
-                               var value:String = comment.substring(ix+1);\r
-                               _comments[key.toUpperCase()]=value;\r
-                       }\r
-               }       \r
-       \r
-               private function readUtf8String(source:ByteArray):String {\r
-                       var length:uint = source.readUnsignedInt();\r
-                       return source.readUTFBytes(length);\r
-               }\r
-       \r
-               public function get vendor():String {\r
-                       return _vendor;\r
-               }\r
-               \r
-               public function get comments():Dictionary {\r
-                       return _comments;\r
-               }\r
-       \r
-               public function get artist():String {\r
-                       return _comments["ARTIST"];\r
-               }\r
-               \r
-               public function get title():String {\r
-                       return _comments["TITLE"];\r
-               }\r
-       \r
-       }\r
-\r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import flash.utils.ByteArray;
+       import flash.utils.Endian;
+       import flash.utils.Dictionary;
+       import org.omtk.ogg.*;
+
+       public class CommentHeader {
+       
+               private var _vendor:String;
+               private var _comments:Dictionary = new Dictionary();
+       
+               public function CommentHeader(source:ByteArray)
+               {
+                       init( source );
+               }
+               
+               private function init( source: ByteArray ): void
+               {
+                       source.readByte();
+                       source.readByte();
+                       source.readByte();
+                       source.readByte();
+                       source.readByte();
+                       source.readByte();
+
+                       _vendor = readUtf8String(source);
+                       
+                       var ucLength:int = source.readUnsignedInt();
+                       
+                       for(var i:int = 0; i < ucLength; i++) {
+                               var comment:String = readUtf8String(source);
+                               var ix:int = comment.indexOf('=');
+                               var key:String = comment.substring(0, ix);
+                               var value:String = comment.substring(ix+1);
+                               _comments[key.toUpperCase()]=value;
+                       }
+               }       
+       
+               private function readUtf8String(source:ByteArray):String {
+                       var length:uint = source.readUnsignedInt();
+                       return source.readUTFBytes(length);
+               }
+       
+               public function get vendor():String {
+                       return _vendor;
+               }
+               
+               public function get comments():Dictionary {
+                       return _comments;
+               }
+       
+               public function get artist():String {
+                       return _comments["ARTIST"];
+               }
+               
+               public function get title():String {
+                       return _comments["TITLE"];
+               }
+       
+       }
+
 }
\ No newline at end of file
index 24295d5..f8eac3b 100644 (file)
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import flash.errors.IllegalOperationError;\r
-       import org.omtk.util.BitByteArray;\r
-       \r
-       public class Floor {\r
-       \r
-               public static const DB_STATIC_TABLE:Vector.<Number> = Vector.<Number>([\r
-                       1.0649863e-07, 1.1341951e-07, 1.2079015e-07, 1.2863978e-07,\r
-                       1.3699951e-07, 1.4590251e-07, 1.5538408e-07, 1.6548181e-07,\r
-                       1.7623575e-07, 1.8768855e-07, 1.9988561e-07, 2.128753e-07,\r
-                       2.2670913e-07, 2.4144197e-07, 2.5713223e-07, 2.7384213e-07,\r
-                       2.9163793e-07, 3.1059021e-07, 3.3077411e-07, 3.5226968e-07,\r
-                       3.7516214e-07, 3.9954229e-07, 4.2550680e-07, 4.5315863e-07,\r
-                       4.8260743e-07, 5.1396998e-07, 5.4737065e-07, 5.8294187e-07,\r
-                       6.2082472e-07, 6.6116941e-07, 7.0413592e-07, 7.4989464e-07,\r
-                       7.9862701e-07, 8.5052630e-07, 9.0579828e-07, 9.6466216e-07,\r
-                       1.0273513e-06, 1.0941144e-06, 1.1652161e-06, 1.2409384e-06,\r
-                       1.3215816e-06, 1.4074654e-06, 1.4989305e-06, 1.5963394e-06,\r
-                       1.7000785e-06, 1.8105592e-06, 1.9282195e-06, 2.0535261e-06,\r
-                       2.1869758e-06, 2.3290978e-06, 2.4804557e-06, 2.6416497e-06,\r
-                       2.8133190e-06, 2.9961443e-06, 3.1908506e-06, 3.3982101e-06,\r
-                       3.6190449e-06, 3.8542308e-06, 4.1047004e-06, 4.3714470e-06,\r
-                       4.6555282e-06, 4.9580707e-06, 5.2802740e-06, 5.6234160e-06,\r
-                       5.9888572e-06, 6.3780469e-06, 6.7925283e-06, 7.2339451e-06,\r
-                       7.7040476e-06, 8.2047000e-06, 8.7378876e-06, 9.3057248e-06,\r
-                       9.9104632e-06, 1.0554501e-05, 1.1240392e-05, 1.1970856e-05,\r
-                       1.2748789e-05, 1.3577278e-05, 1.4459606e-05, 1.5399272e-05,\r
-                       1.6400004e-05, 1.7465768e-05, 1.8600792e-05, 1.9809576e-05,\r
-                       2.1096914e-05, 2.2467911e-05, 2.3928002e-05, 2.5482978e-05,\r
-                       2.7139006e-05, 2.8902651e-05, 3.0780908e-05, 3.2781225e-05,\r
-                       3.4911534e-05, 3.7180282e-05, 3.9596466e-05, 4.2169667e-05,\r
-                       4.4910090e-05, 4.7828601e-05, 5.0936773e-05, 5.4246931e-05,\r
-                       5.7772202e-05, 6.1526565e-05, 6.5524908e-05, 6.9783085e-05,\r
-                       7.4317983e-05, 7.9147585e-05, 8.4291040e-05, 8.9768747e-05,\r
-                       9.5602426e-05, 0.00010181521, 0.00010843174, 0.00011547824,\r
-                       0.00012298267, 0.00013097477, 0.00013948625, 0.00014855085,\r
-                       0.00015820453, 0.00016848555, 0.00017943469, 0.00019109536,\r
-                       0.00020351382, 0.00021673929, 0.00023082423, 0.00024582449,\r
-                       0.00026179955, 0.00027881276, 0.00029693158, 0.00031622787,\r
-                       0.00033677814, 0.00035866388, 0.00038197188, 0.00040679456,\r
-                       0.00043323036, 0.00046138411, 0.00049136745, 0.00052329927,\r
-                       0.00055730621, 0.00059352311, 0.00063209358, 0.00067317058,\r
-                       0.00071691700, 0.00076350630, 0.00081312324, 0.00086596457,\r
-                       0.00092223983, 0.00098217216, 0.0010459992, 0.0011139742,\r
-                       0.0011863665, 0.0012634633, 0.0013455702, 0.0014330129,\r
-                       0.0015261382, 0.0016253153, 0.0017309374, 0.0018434235,\r
-                       0.0019632195, 0.0020908006, 0.0022266726, 0.0023713743,\r
-                       0.0025254795, 0.0026895994, 0.0028643847, 0.0030505286,\r
-                       0.0032487691, 0.0034598925, 0.0036847358, 0.0039241906,\r
-                       0.0041792066, 0.0044507950, 0.0047400328, 0.0050480668,\r
-                       0.0053761186, 0.0057254891, 0.0060975636, 0.0064938176,\r
-                       0.0069158225, 0.0073652516, 0.0078438871, 0.0083536271,\r
-                       0.0088964928, 0.009474637, 0.010090352, 0.010746080,\r
-                       0.011444421, 0.012188144, 0.012980198, 0.013823725,\r
-                       0.014722068, 0.015678791, 0.016697687, 0.017782797,\r
-                       0.018938423, 0.020169149, 0.021479854, 0.022875735,\r
-                       0.024362330, 0.025945531, 0.027631618, 0.029427276,\r
-                       0.031339626, 0.033376252, 0.035545228, 0.037855157,\r
-                       0.040315199, 0.042935108, 0.045725273, 0.048696758,\r
-                       0.051861348, 0.055231591, 0.058820850, 0.062643361,\r
-                       0.066714279, 0.071049749, 0.075666962, 0.080584227,\r
-                       0.085821044, 0.091398179, 0.097337747, 0.10366330,\r
-                       0.11039993, 0.11757434, 0.12521498, 0.13335215,\r
-                       0.14201813, 0.15124727, 0.16107617, 0.17154380,\r
-                       0.18269168, 0.19456402, 0.20720788, 0.22067342,\r
-                       0.23501402, 0.25028656, 0.26655159, 0.28387361,\r
-                       0.30232132, 0.32196786, 0.34289114, 0.36517414,\r
-                       0.38890521, 0.41417847, 0.44109412, 0.46975890,\r
-                       0.50028648, 0.53279791, 0.56742212, 0.60429640,\r
-                       0.64356699, 0.68538959, 0.72993007, 0.77736504,\r
-                       0.82788260, 0.88168307, 0.9389798, 1.0]);\r
-       \r
-               public static function createInstance(source:BitByteArray, header:SetupHeader):Floor {\r
-       \r
-                       var type:int = source.readUnsignedBitwiseInt(16);\r
-       \r
-                       switch (type) {\r
-                       case 0:\r
-                               return new Floor0(source, header);\r
-                       case 1:\r
-                               return new Floor1(source, header);\r
-                       default:\r
-                               throw new Error("Floor type " + type + " is not supported.");\r
-                       }\r
-               }\r
-\r
-               public function get type():int {\r
-                       throw new IllegalOperationError("operation not implemented");\r
-               }\r
-               \r
-               public function decodeFloor(vorbis:VorbisStream, source:BitByteArray):Floor1 {\r
-                       throw new IllegalOperationError("operation not implemented");\r
-               }\r
-       \r
-               public function computeFloor(vector:Vector.<Number>):void {\r
-                       throw new IllegalOperationError("operation not implemented");\r
-               }\r
-               \r
-\r
-       }\r
-\r
-       \r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import flash.errors.IllegalOperationError;
+       import org.omtk.util.BitByteArray;
+       
+       public class Floor {
+       
+               public static const DB_STATIC_TABLE:Vector.<Number> = Vector.<Number>([
+                       1.0649863e-07, 1.1341951e-07, 1.2079015e-07, 1.2863978e-07,
+                       1.3699951e-07, 1.4590251e-07, 1.5538408e-07, 1.6548181e-07,
+                       1.7623575e-07, 1.8768855e-07, 1.9988561e-07, 2.128753e-07,
+                       2.2670913e-07, 2.4144197e-07, 2.5713223e-07, 2.7384213e-07,
+                       2.9163793e-07, 3.1059021e-07, 3.3077411e-07, 3.5226968e-07,
+                       3.7516214e-07, 3.9954229e-07, 4.2550680e-07, 4.5315863e-07,
+                       4.8260743e-07, 5.1396998e-07, 5.4737065e-07, 5.8294187e-07,
+                       6.2082472e-07, 6.6116941e-07, 7.0413592e-07, 7.4989464e-07,
+                       7.9862701e-07, 8.5052630e-07, 9.0579828e-07, 9.6466216e-07,
+                       1.0273513e-06, 1.0941144e-06, 1.1652161e-06, 1.2409384e-06,
+                       1.3215816e-06, 1.4074654e-06, 1.4989305e-06, 1.5963394e-06,
+                       1.7000785e-06, 1.8105592e-06, 1.9282195e-06, 2.0535261e-06,
+                       2.1869758e-06, 2.3290978e-06, 2.4804557e-06, 2.6416497e-06,
+                       2.8133190e-06, 2.9961443e-06, 3.1908506e-06, 3.3982101e-06,
+                       3.6190449e-06, 3.8542308e-06, 4.1047004e-06, 4.3714470e-06,
+                       4.6555282e-06, 4.9580707e-06, 5.2802740e-06, 5.6234160e-06,
+                       5.9888572e-06, 6.3780469e-06, 6.7925283e-06, 7.2339451e-06,
+                       7.7040476e-06, 8.2047000e-06, 8.7378876e-06, 9.3057248e-06,
+                       9.9104632e-06, 1.0554501e-05, 1.1240392e-05, 1.1970856e-05,
+                       1.2748789e-05, 1.3577278e-05, 1.4459606e-05, 1.5399272e-05,
+                       1.6400004e-05, 1.7465768e-05, 1.8600792e-05, 1.9809576e-05,
+                       2.1096914e-05, 2.2467911e-05, 2.3928002e-05, 2.5482978e-05,
+                       2.7139006e-05, 2.8902651e-05, 3.0780908e-05, 3.2781225e-05,
+                       3.4911534e-05, 3.7180282e-05, 3.9596466e-05, 4.2169667e-05,
+                       4.4910090e-05, 4.7828601e-05, 5.0936773e-05, 5.4246931e-05,
+                       5.7772202e-05, 6.1526565e-05, 6.5524908e-05, 6.9783085e-05,
+                       7.4317983e-05, 7.9147585e-05, 8.4291040e-05, 8.9768747e-05,
+                       9.5602426e-05, 0.00010181521, 0.00010843174, 0.00011547824,
+                       0.00012298267, 0.00013097477, 0.00013948625, 0.00014855085,
+                       0.00015820453, 0.00016848555, 0.00017943469, 0.00019109536,
+                       0.00020351382, 0.00021673929, 0.00023082423, 0.00024582449,
+                       0.00026179955, 0.00027881276, 0.00029693158, 0.00031622787,
+                       0.00033677814, 0.00035866388, 0.00038197188, 0.00040679456,
+                       0.00043323036, 0.00046138411, 0.00049136745, 0.00052329927,
+                       0.00055730621, 0.00059352311, 0.00063209358, 0.00067317058,
+                       0.00071691700, 0.00076350630, 0.00081312324, 0.00086596457,
+                       0.00092223983, 0.00098217216, 0.0010459992, 0.0011139742,
+                       0.0011863665, 0.0012634633, 0.0013455702, 0.0014330129,
+                       0.0015261382, 0.0016253153, 0.0017309374, 0.0018434235,
+                       0.0019632195, 0.0020908006, 0.0022266726, 0.0023713743,
+                       0.0025254795, 0.0026895994, 0.0028643847, 0.0030505286,
+                       0.0032487691, 0.0034598925, 0.0036847358, 0.0039241906,
+                       0.0041792066, 0.0044507950, 0.0047400328, 0.0050480668,
+                       0.0053761186, 0.0057254891, 0.0060975636, 0.0064938176,
+                       0.0069158225, 0.0073652516, 0.0078438871, 0.0083536271,
+                       0.0088964928, 0.009474637, 0.010090352, 0.010746080,
+                       0.011444421, 0.012188144, 0.012980198, 0.013823725,
+                       0.014722068, 0.015678791, 0.016697687, 0.017782797,
+                       0.018938423, 0.020169149, 0.021479854, 0.022875735,
+                       0.024362330, 0.025945531, 0.027631618, 0.029427276,
+                       0.031339626, 0.033376252, 0.035545228, 0.037855157,
+                       0.040315199, 0.042935108, 0.045725273, 0.048696758,
+                       0.051861348, 0.055231591, 0.058820850, 0.062643361,
+                       0.066714279, 0.071049749, 0.075666962, 0.080584227,
+                       0.085821044, 0.091398179, 0.097337747, 0.10366330,
+                       0.11039993, 0.11757434, 0.12521498, 0.13335215,
+                       0.14201813, 0.15124727, 0.16107617, 0.17154380,
+                       0.18269168, 0.19456402, 0.20720788, 0.22067342,
+                       0.23501402, 0.25028656, 0.26655159, 0.28387361,
+                       0.30232132, 0.32196786, 0.34289114, 0.36517414,
+                       0.38890521, 0.41417847, 0.44109412, 0.46975890,
+                       0.50028648, 0.53279791, 0.56742212, 0.60429640,
+                       0.64356699, 0.68538959, 0.72993007, 0.77736504,
+                       0.82788260, 0.88168307, 0.9389798, 1.0]);
+       
+               public static function createInstance(source:BitByteArray, header:SetupHeader):Floor {
+       
+                       var type:int = source.readUnsignedBitwiseInt(16);
+       
+                       switch (type) {
+                       case 0:
+                               return new Floor0(source, header);
+                       case 1:
+                               return new Floor1(source, header);
+                       default:
+                               throw new Error("Floor type " + type + " is not supported.");
+                       }
+               }
+
+               public function get type():int {
+                       throw new IllegalOperationError("operation not implemented");
+               }
+               
+               public function decodeFloor(vorbis:VorbisStream, source:BitByteArray):Floor1 {
+                       throw new IllegalOperationError("operation not implemented");
+               }
+       
+               public function computeFloor(vector:Vector.<Number>):void {
+                       throw new IllegalOperationError("operation not implemented");
+               }
+               
+
+       }
+
+       
 }
\ No newline at end of file
index 064a0a1..3f38dc8 100644 (file)
@@ -1,56 +1,56 @@
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import flash.errors.IllegalOperationError;\r
-       import org.omtk.util.BitByteArray;\r
-       \r
-       public class Floor0 extends Floor {\r
-\r
-               private var order:int;\r
-               private var rate:int;\r
-               private var barkMapSize:int;\r
-               private var amplitudeBits:int;\r
-               private var amplitudeOffset:int;\r
-               \r
-               private var bookList:Vector.<int>;\r
-               \r
-               public function Floor0(source:BitByteArray, header:SetupHeader) {\r
-\r
-                       order = source.readUnsignedBitwiseInt(8);\r
-                       rate = source.readUnsignedBitwiseInt(16);\r
-                       barkMapSize = source.readUnsignedBitwiseInt(16);\r
-                       amplitudeBits = source.readUnsignedBitwiseInt(6);\r
-                       amplitudeOffset = source.readUnsignedBitwiseInt(8);\r
-       \r
-                       var bookCount:uint = source.readUnsignedBitwiseInt(4) + 1;\r
-                       bookList = new Vector.<int>(bookCount);\r
-       \r
-                       var i:int;\r
-       \r
-                       for (i = 0; i < bookList.length; i++) {\r
-                               bookList[i] = source.readUnsignedBitwiseInt(8);\r
-                               if (bookList[i] > header.codeBooks.length) {\r
-                                       throw new Error("A floor0_book_list entry is higher than the code book count.");\r
-                               }\r
-                       }\r
-               }\r
-\r
-       }\r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import flash.errors.IllegalOperationError;
+       import org.omtk.util.BitByteArray;
+       
+       public class Floor0 extends Floor {
+
+               private var order:int;
+               private var rate:int;
+               private var barkMapSize:int;
+               private var amplitudeBits:int;
+               private var amplitudeOffset:int;
+               
+               private var bookList:Vector.<int>;
+               
+               public function Floor0(source:BitByteArray, header:SetupHeader) {
+
+                       order = source.readUnsignedBitwiseInt(8);
+                       rate = source.readUnsignedBitwiseInt(16);
+                       barkMapSize = source.readUnsignedBitwiseInt(16);
+                       amplitudeBits = source.readUnsignedBitwiseInt(6);
+                       amplitudeOffset = source.readUnsignedBitwiseInt(8);
+       
+                       var bookCount:uint = source.readUnsignedBitwiseInt(4) + 1;
+                       bookList = new Vector.<int>(bookCount);
+       
+                       var i:int;
+       
+                       for (i = 0; i < bookList.length; i++) {
+                               bookList[i] = source.readUnsignedBitwiseInt(8);
+                               if (bookList[i] > header.codeBooks.length) {
+                                       throw new Error("A floor0_book_list entry is higher than the code book count.");
+                               }
+                       }
+               }
+
+       }
 }
\ No newline at end of file
index 068d817..70621d0 100644 (file)
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import flash.errors.IllegalOperationError;\r
-       import org.omtk.util.*;\r
-       \r
-       public class Floor1 extends Floor {\r
-\r
-               private var partitionClassList:Vector.<int>;\r
-               private var maximumClass:int;\r
-               private var multiplier:int;\r
-               private var rangeBits:int;\r
-               private var classDimensions:Vector.<int>;\r
-               private var classSubclasses:Vector.<int>;\r
-               private var classMasterbooks:Vector.<int>;\r
-               private var subclassBooks:Vector.<Vector.<int>>;\r
-               private var xList:Vector.<int>;\r
-               private var yList:Vector.<int>;\r
-               private var lowNeighbours:Vector.<int>;\r
-               private var highNeighbours:Vector.<int>;\r
-               private static var RANGES:Vector.<int> = Vector.<int>([256, 128, 86, 64]);\r
-\r
-               private var xList2:Vector.<int>;\r
-               private var step2Flags:Vector.<Boolean>;\r
-               \r
-               public function Floor1(source:BitByteArray = null, header:SetupHeader = null) {\r
-\r
-                       if(source==null && header==null) {\r
-                               return;\r
-                       }\r
-               \r
-                       var i:int;\r
-                       var j:int;\r
-                       \r
-                       maximumClass = -1;\r
-                       var partitions:int = source.readUnsignedBitwiseInt(5);\r
-                       partitionClassList = new Vector.<int>(partitions);\r
-       \r
-                       for (i = 0; i < partitionClassList.length; i++) {\r
-                               partitionClassList[i] = source.readUnsignedBitwiseInt(4);\r
-                               if (partitionClassList[i] > maximumClass) {\r
-                                       maximumClass = partitionClassList[i];\r
-                               }\r
-                       }\r
-       \r
-                       classDimensions = new Vector.<int>(maximumClass + 1);\r
-                       classSubclasses = new Vector.<int>(maximumClass + 1);\r
-                       classMasterbooks = new Vector.<int>(maximumClass + 1);\r
-                       subclassBooks = new Vector.<Vector.<int>>(maximumClass + 1);\r
-       \r
-                       var xListLength:int = 2;\r
-       \r
-                       for (i = 0; i <= maximumClass; i++) {\r
-                               classDimensions[i] = source.readUnsignedBitwiseInt(3) + 1;\r
-                               xListLength += classDimensions[i];\r
-                               classSubclasses[i] = source.readUnsignedBitwiseInt(2);\r
-       \r
-                               if (classDimensions[i] > header.codeBooks.length || classSubclasses[i] > header.codeBooks.length) {\r
-                                       throw new Error("There is a class dimension or class subclasses entry higher than the number of codebooks in the setup header.");\r
-                               }\r
-                               if (classSubclasses[i] != 0) {\r
-                                       classMasterbooks[i] = source.readUnsignedBitwiseInt(8);\r
-                               }\r
-                               subclassBooks[i] = new Vector.<int>(1 << classSubclasses[i]);\r
-                               for (j = 0; j < subclassBooks[i].length; j++) {\r
-                                       subclassBooks[i][j] = source.readUnsignedBitwiseInt(8) - 1;\r
-                               }\r
-                       }\r
-       \r
-                       multiplier = source.readUnsignedBitwiseInt(2) + 1;\r
-                       rangeBits = source.readUnsignedBitwiseInt(4);\r
-       \r
-                       var floorValues:int = 0;\r
-       \r
-                       xList = Vector.<int>([0, 1<<rangeBits]);\r
-                       \r
-                       for (i = 0; i < partitions; i++) {\r
-                               for (j = 0; j < classDimensions[partitionClassList[i]]; j++) {\r
-                                       xList.push(source.readUnsignedBitwiseInt(rangeBits));\r
-                               }\r
-                       }\r
-       \r
-                       lowNeighbours = new Vector.<int>(xList.length);\r
-                       highNeighbours = new Vector.<int>(xList.length);\r
-       \r
-                       for (i = 0; i < xList.length; i++) {\r
-                               lowNeighbours[i] = Util.lowNeighbour(xList, i);\r
-                               highNeighbours[i] = Util.highNeighbour(xList, i);\r
-                       }\r
-                       \r
-                       xList2 = new Vector.<int>(xList.length, true);\r
-                       step2Flags = new Vector.<Boolean>(xList.length, true);\r
-               }\r
-\r
-               public override function get type():int {\r
-                       return 1;\r
-               }\r
-\r
-               public override function decodeFloor(vorbis:VorbisStream, source:BitByteArray):Floor1 {\r
-\r
-                       var i:int;\r
-                       var j:int;\r
-                       var offset:int;\r
-\r
-                       if (!source.readBit()) {\r
-                               return null;\r
-                       }\r
-       \r
-                       var clone:Floor1 = clone();\r
-       \r
-                       clone.yList = new Vector.<int>(xList.length);\r
-       \r
-                       var range:int = RANGES[multiplier - 1];\r
-       \r
-                       clone.yList[0] = source.readUnsignedBitwiseInt(Util.ilog(range - 1));\r
-                       clone.yList[1] = source.readUnsignedBitwiseInt(Util.ilog(range - 1));\r
-       \r
-                       offset = 2;\r
-       \r
-                       for (i = 0; i < partitionClassList.length; i++) {\r
-                               var cls:int = partitionClassList[i];\r
-                               var cdim:int = classDimensions[cls];\r
-                               var cbits:int = classSubclasses[cls];\r
-                               var csub:int = (1 << cbits) - 1;\r
-                               var cval:int = 0;\r
-                               if (cbits > 0) {\r
-                                       cval = source.readUnsignedHuffmanInt(vorbis.setupHeader.codeBooks[classMasterbooks[cls]].huffmanRoot);\r
-                               }\r
-\r
-                               for (j = 0; j < cdim; j++) {\r
-                                       var book:int = subclassBooks[cls][cval & csub];\r
-                                       cval >>>= cbits;\r
-                                       if (book >= 0) {\r
-                                               clone.yList[j + offset] = source.readUnsignedHuffmanInt(vorbis.setupHeader.codeBooks[book].huffmanRoot);\r
-                                       } else {\r
-                                               clone.yList[j + offset] = 0;\r
-                                       }\r
-                               }\r
-                               offset += cdim;\r
-                       }\r
-               \r
-                       return clone;\r
-               }\r
-       \r
-               public override function computeFloor(vector:Vector.<Number>):void {\r
-\r
-                       var i:int;\r
-                       var j:int;\r
-\r
-                       var n:int = vector.length;\r
-                       var values:int = xList.length;\r
-                       //var step2Flags:Vector.<Boolean> = new Vector.<Boolean>(values);\r
-\r
-                       var range:int = RANGES[multiplier - 1];\r
-       \r
-                       for (i = 2; i < values; i++) {\r
-\r
-                               var lowNeighbourOffset:int = lowNeighbours[i];\r
-                               var highNeighbourOffset:int = highNeighbours[i];\r
-                               \r
-                               var predicted:int = Util.renderPoint(\r
-                                       xList[lowNeighbourOffset], xList[highNeighbourOffset], \r
-                                       yList[lowNeighbourOffset], yList[highNeighbourOffset], xList[i]);\r
-                               \r
-                               var val:int = yList[i];\r
-                               var highRoom:int = range - predicted;\r
-                               var lowRoom:int = predicted;\r
-                               var room:int = highRoom < lowRoom ? highRoom * 2 : lowRoom * 2;\r
-                               \r
-                               if (val != 0) {\r
-                                       step2Flags[lowNeighbourOffset] = true;\r
-                                       step2Flags[highNeighbourOffset] = true;\r
-                                       step2Flags[i] = true;\r
-                                       if (val >= room) {\r
-                                               yList[i] = highRoom > lowRoom ? val - lowRoom + predicted\r
-                                                               : -val + highRoom + predicted - 1;\r
-                                       } else {\r
-                                               yList[i] = (val & 1) == 1 ? predicted - ((val + 1) >> 1)\r
-                                                               : predicted + (val >> 1);\r
-                                       }\r
-                               } else {\r
-                                       step2Flags[i] = false;\r
-                                       yList[i] = predicted;\r
-                               }\r
-                       }\r
-       \r
-                       for(i=0; i<xList.length; i++) {\r
-                               xList2[i] = xList[i];\r
-                       }\r
-\r
-                       sort(xList2, yList, step2Flags);\r
-       \r
-                       var hx:int = 0;\r
-                       var hy:int = 0;\r
-                       var lx:int = 0;\r
-                       var ly:int = yList[0] * multiplier;\r
-       \r
-                       for (i = 1; i < values; i++) {\r
-                               if (step2Flags[i]) {\r
-                                       hy = yList[i] * multiplier;\r
-                                       hx = xList2[i];\r
-                                       Util.renderLine(lx, ly, hx, hy, vector);\r
-                                       lx = hx;\r
-                                       ly = hy;\r
-                               }\r
-                       }\r
-       \r
-                       var r:Number = DB_STATIC_TABLE[hy];\r
-\r
-                       while(hx < n/2) {\r
-                               vector[hx++] = r;\r
-                       }\r
-\r
-               }\r
-\r
-               public function clone():Floor1 {\r
-                       var clone:Floor1 = new Floor1();\r
-                       clone.classDimensions = classDimensions;\r
-                       clone.classMasterbooks = classMasterbooks;\r
-                       clone.classSubclasses = classSubclasses;\r
-                       clone.maximumClass = maximumClass;\r
-                       clone.multiplier = multiplier;\r
-                       clone.partitionClassList = partitionClassList;\r
-                       clone.rangeBits = rangeBits;\r
-                       clone.subclassBooks = subclassBooks;\r
-                       clone.xList = xList;\r
-                       clone.yList = yList;\r
-                       clone.lowNeighbours = lowNeighbours;\r
-                       clone.highNeighbours = highNeighbours;\r
-                       clone.xList2 = xList2;\r
-                       clone.step2Flags = step2Flags;\r
-                       return clone;\r
-               }\r
-               \r
-               private function sort(x:Vector.<int>, y:Vector.<int>, b:Vector.<Boolean>):void {\r
-                       var off:int = 0;\r
-                       var len:int = x.length;\r
-                       var lim:int = len + off;\r
-                       var itmp:int;\r
-                       var btmp:Boolean;\r
-                       var i:int;\r
-                       var j:int;\r
-                       // Insertion sort on smallest arrays\r
-                       for (i = off; i < lim; i++) {\r
-                               for (j = i; j > off && x[j - 1] > x[j]; j--) {\r
-                                       itmp = x[j];\r
-                                       x[j] = x[j - 1];\r
-                                       x[j - 1] = itmp;\r
-                                       itmp = y[j];\r
-                                       y[j] = y[j - 1];\r
-                                       y[j - 1] = itmp;\r
-                                       btmp = b[j];\r
-                                       b[j] = b[j - 1];\r
-                                       b[j - 1] = btmp;\r
-                               }\r
-                       }\r
-               }\r
-\r
-       }\r
-       \r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import flash.errors.IllegalOperationError;
+       import org.omtk.util.*;
+       
+       public class Floor1 extends Floor {
+
+               private var partitionClassList:Vector.<int>;
+               private var maximumClass:int;
+               private var multiplier:int;
+               private var rangeBits:int;
+               private var classDimensions:Vector.<int>;
+               private var classSubclasses:Vector.<int>;
+               private var classMasterbooks:Vector.<int>;
+               private var subclassBooks:Vector.<Vector.<int>>;
+               private var xList:Vector.<int>;
+               private var yList:Vector.<int>;
+               private var lowNeighbours:Vector.<int>;
+               private var highNeighbours:Vector.<int>;
+               private static var RANGES:Vector.<int> = Vector.<int>([256, 128, 86, 64]);
+
+               private var xList2:Vector.<int>;
+               private var step2Flags:Vector.<Boolean>;
+               
+               public function Floor1(source:BitByteArray = null, header:SetupHeader = null) {
+
+                       if(source==null && header==null) {
+                               return;
+                       }
+               
+                       var i:int;
+                       var j:int;
+                       
+                       maximumClass = -1;
+                       var partitions:int = source.readUnsignedBitwiseInt(5);
+                       partitionClassList = new Vector.<int>(partitions);
+       
+                       for (i = 0; i < partitionClassList.length; i++) {
+                               partitionClassList[i] = source.readUnsignedBitwiseInt(4);
+                               if (partitionClassList[i] > maximumClass) {
+                                       maximumClass = partitionClassList[i];
+                               }
+                       }
+       
+                       classDimensions = new Vector.<int>(maximumClass + 1);
+                       classSubclasses = new Vector.<int>(maximumClass + 1);
+                       classMasterbooks = new Vector.<int>(maximumClass + 1);
+                       subclassBooks = new Vector.<Vector.<int>>(maximumClass + 1);
+       
+                       var xListLength:int = 2;
+       
+                       for (i = 0; i <= maximumClass; i++) {
+                               classDimensions[i] = source.readUnsignedBitwiseInt(3) + 1;
+                               xListLength += classDimensions[i];
+                               classSubclasses[i] = source.readUnsignedBitwiseInt(2);
+       
+                               if (classDimensions[i] > header.codeBooks.length || classSubclasses[i] > header.codeBooks.length) {
+                                       throw new Error("There is a class dimension or class subclasses entry higher than the number of codebooks in the setup header.");
+                               }
+                               if (classSubclasses[i] != 0) {
+                                       classMasterbooks[i] = source.readUnsignedBitwiseInt(8);
+                               }
+                               subclassBooks[i] = new Vector.<int>(1 << classSubclasses[i]);
+                               for (j = 0; j < subclassBooks[i].length; j++) {
+                                       subclassBooks[i][j] = source.readUnsignedBitwiseInt(8) - 1;
+                               }
+                       }
+       
+                       multiplier = source.readUnsignedBitwiseInt(2) + 1;
+                       rangeBits = source.readUnsignedBitwiseInt(4);
+       
+                       var floorValues:int = 0;
+       
+                       xList = Vector.<int>([0, 1<<rangeBits]);
+                       
+                       for (i = 0; i < partitions; i++) {
+                               for (j = 0; j < classDimensions[partitionClassList[i]]; j++) {
+                                       xList.push(source.readUnsignedBitwiseInt(rangeBits));
+                               }
+                       }
+       
+                       lowNeighbours = new Vector.<int>(xList.length);
+                       highNeighbours = new Vector.<int>(xList.length);
+       
+                       for (i = 0; i < xList.length; i++) {
+                               lowNeighbours[i] = Util.lowNeighbour(xList, i);
+                               highNeighbours[i] = Util.highNeighbour(xList, i);
+                       }
+                       
+                       xList2 = new Vector.<int>(xList.length, true);
+                       step2Flags = new Vector.<Boolean>(xList.length, true);
+               }
+
+               public override function get type():int {
+                       return 1;
+               }
+
+               public override function decodeFloor(vorbis:VorbisStream, source:BitByteArray):Floor1 {
+
+                       var i:int;
+                       var j:int;
+                       var offset:int;
+
+                       if (!source.readBit()) {
+                               return null;
+                       }
+       
+                       var clone:Floor1 = clone();
+       
+                       clone.yList = new Vector.<int>(xList.length);
+       
+                       var range:int = RANGES[multiplier - 1];
+       
+                       clone.yList[0] = source.readUnsignedBitwiseInt(Util.ilog(range - 1));
+                       clone.yList[1] = source.readUnsignedBitwiseInt(Util.ilog(range - 1));
+       
+                       offset = 2;
+       
+                       for (i = 0; i < partitionClassList.length; i++) {
+                               var cls:int = partitionClassList[i];
+                               var cdim:int = classDimensions[cls];
+                               var cbits:int = classSubclasses[cls];
+                               var csub:int = (1 << cbits) - 1;
+                               var cval:int = 0;
+                               if (cbits > 0) {
+                                       cval = source.readUnsignedHuffmanInt(vorbis.setupHeader.codeBooks[classMasterbooks[cls]].huffmanRoot);
+                               }
+
+                               for (j = 0; j < cdim; j++) {
+                                       var book:int = subclassBooks[cls][cval & csub];
+                                       cval >>>= cbits;
+                                       if (book >= 0) {
+                                               clone.yList[j + offset] = source.readUnsignedHuffmanInt(vorbis.setupHeader.codeBooks[book].huffmanRoot);
+                                       } else {
+                                               clone.yList[j + offset] = 0;
+                                       }
+                               }
+                               offset += cdim;
+                       }
+               
+                       return clone;
+               }
+       
+               public override function computeFloor(vector:Vector.<Number>):void {
+
+                       var i:int;
+                       var j:int;
+
+                       var n:int = vector.length;
+                       var values:int = xList.length;
+                       //var step2Flags:Vector.<Boolean> = new Vector.<Boolean>(values);
+
+                       var range:int = RANGES[multiplier - 1];
+       
+                       for (i = 2; i < values; i++) {
+
+                               var lowNeighbourOffset:int = lowNeighbours[i];
+                               var highNeighbourOffset:int = highNeighbours[i];
+                               
+                               var predicted:int = Util.renderPoint(
+                                       xList[lowNeighbourOffset], xList[highNeighbourOffset], 
+                                       yList[lowNeighbourOffset], yList[highNeighbourOffset], xList[i]);
+                               
+                               var val:int = yList[i];
+                               var highRoom:int = range - predicted;
+                               var lowRoom:int = predicted;
+                               var room:int = highRoom < lowRoom ? highRoom * 2 : lowRoom * 2;
+                               
+                               if (val != 0) {
+                                       step2Flags[lowNeighbourOffset] = true;
+                                       step2Flags[highNeighbourOffset] = true;
+                                       step2Flags[i] = true;
+                                       if (val >= room) {
+                                               yList[i] = highRoom > lowRoom ? val - lowRoom + predicted
+                                                               : -val + highRoom + predicted - 1;
+                                       } else {
+                                               yList[i] = (val & 1) == 1 ? predicted - ((val + 1) >> 1)
+                                                               : predicted + (val >> 1);
+                                       }
+                               } else {
+                                       step2Flags[i] = false;
+                                       yList[i] = predicted;
+                               }
+                       }
+       
+                       for(i=0; i<xList.length; i++) {
+                               xList2[i] = xList[i];
+                       }
+
+                       sort(xList2, yList, step2Flags);
+       
+                       var hx:int = 0;
+                       var hy:int = 0;
+                       var lx:int = 0;
+                       var ly:int = yList[0] * multiplier;
+       
+                       for (i = 1; i < values; i++) {
+                               if (step2Flags[i]) {
+                                       hy = yList[i] * multiplier;
+                                       hx = xList2[i];
+                                       Util.renderLine(lx, ly, hx, hy, vector);
+                                       lx = hx;
+                                       ly = hy;
+                               }
+                       }
+       
+                       var r:Number = DB_STATIC_TABLE[hy];
+
+                       while(hx < n/2) {
+                               vector[hx++] = r;
+                       }
+
+               }
+
+               public function clone():Floor1 {
+                       var clone:Floor1 = new Floor1();
+                       clone.classDimensions = classDimensions;
+                       clone.classMasterbooks = classMasterbooks;
+                       clone.classSubclasses = classSubclasses;
+                       clone.maximumClass = maximumClass;
+                       clone.multiplier = multiplier;
+                       clone.partitionClassList = partitionClassList;
+                       clone.rangeBits = rangeBits;
+                       clone.subclassBooks = subclassBooks;
+                       clone.xList = xList;
+                       clone.yList = yList;
+                       clone.lowNeighbours = lowNeighbours;
+                       clone.highNeighbours = highNeighbours;
+                       clone.xList2 = xList2;
+                       clone.step2Flags = step2Flags;
+                       return clone;
+               }
+               
+               private function sort(x:Vector.<int>, y:Vector.<int>, b:Vector.<Boolean>):void {
+                       var off:int = 0;
+                       var len:int = x.length;
+                       var lim:int = len + off;
+                       var itmp:int;
+                       var btmp:Boolean;
+                       var i:int;
+                       var j:int;
+                       // Insertion sort on smallest arrays
+                       for (i = off; i < lim; i++) {
+                               for (j = i; j > off && x[j - 1] > x[j]; j--) {
+                                       itmp = x[j];
+                                       x[j] = x[j - 1];
+                                       x[j - 1] = itmp;
+                                       itmp = y[j];
+                                       y[j] = y[j - 1];
+                                       y[j - 1] = itmp;
+                                       btmp = b[j];
+                                       b[j] = b[j - 1];
+                                       b[j - 1] = btmp;
+                               }
+                       }
+               }
+
+       }
+       
 }
\ No newline at end of file
index e78ff2e..c334a11 100644 (file)
@@ -1,87 +1,87 @@
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import flash.utils.ByteArray;\r
-       \r
-       public class IdentificationHeader {\r
-       \r
-               private var _version:uint;\r
-               private var _channels:uint;\r
-               private var _sampleRate:uint;\r
-               private var _bitrateMaximum:int;\r
-               private var _bitrateMinimum:int;\r
-               private var _bitrateNominal:int;\r
-               private var _blockSize0:uint;\r
-               private var _blockSize1:uint;\r
-       \r
-               private var _mdct:Vector.<Mdct>;\r
-\r
-               public function IdentificationHeader(source:ByteArray) {\r
-\r
-                       source.readByte();\r
-                       source.readByte();\r
-                       source.readByte();\r
-                       source.readByte();\r
-                       source.readByte();\r
-                       source.readByte();\r
-       \r
-                       _version = source.readUnsignedInt();\r
-                       _channels = source.readUnsignedByte();\r
-                       _sampleRate = source.readUnsignedInt();\r
-                       _bitrateMaximum = source.readUnsignedInt();\r
-                       _bitrateNominal = source.readUnsignedInt();\r
-                       _bitrateMinimum = source.readUnsignedInt();\r
-                       var bs:int = source.readUnsignedByte();\r
-                       _blockSize0 = 1<<(bs&0xf);\r
-                       _blockSize1 = 1<<(bs>>4);\r
-               \r
-                       _mdct = new Vector.<Mdct>(2, false);\r
-                       _mdct[0] = new Mdct(_blockSize0);\r
-                       _mdct[1] = new Mdct(_blockSize1);\r
-               }\r
-               \r
-               public function get channels():uint {\r
-                       return _channels;\r
-               }\r
-               \r
-               public function get sampleRate():uint {\r
-                       return _sampleRate;\r
-               }\r
-               \r
-               public function get blockSize0():uint {\r
-                       return _blockSize0;\r
-               }\r
-               \r
-               public function get blockSize1():uint {\r
-                       return _blockSize1;\r
-               }\r
-               \r
-               public function get mdct0():Mdct {\r
-                       return _mdct[0];\r
-               }\r
-       \r
-               public function get mdct1():Mdct {\r
-                       return _mdct[1];\r
-               }\r
-\r
-       }\r
-\r
-\r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import flash.utils.ByteArray;
+       
+       public class IdentificationHeader {
+       
+               private var _version:uint;
+               private var _channels:uint;
+               private var _sampleRate:uint;
+               private var _bitrateMaximum:int;
+               private var _bitrateMinimum:int;
+               private var _bitrateNominal:int;
+               private var _blockSize0:uint;
+               private var _blockSize1:uint;
+       
+               private var _mdct:Vector.<Mdct>;
+
+               public function IdentificationHeader(source:ByteArray) {
+
+                       source.readByte();
+                       source.readByte();
+                       source.readByte();
+                       source.readByte();
+                       source.readByte();
+                       source.readByte();
+       
+                       _version = source.readUnsignedInt();
+                       _channels = source.readUnsignedByte();
+                       _sampleRate = source.readUnsignedInt();
+                       _bitrateMaximum = source.readUnsignedInt();
+                       _bitrateNominal = source.readUnsignedInt();
+                       _bitrateMinimum = source.readUnsignedInt();
+                       var bs:int = source.readUnsignedByte();
+                       _blockSize0 = 1<<(bs&0xf);
+                       _blockSize1 = 1<<(bs>>4);
+               
+                       _mdct = new Vector.<Mdct>(2, false);
+                       _mdct[0] = new Mdct(_blockSize0);
+                       _mdct[1] = new Mdct(_blockSize1);
+               }
+               
+               public function get channels():uint {
+                       return _channels;
+               }
+               
+               public function get sampleRate():uint {
+                       return _sampleRate;
+               }
+               
+               public function get blockSize0():uint {
+                       return _blockSize0;
+               }
+               
+               public function get blockSize1():uint {
+                       return _blockSize1;
+               }
+               
+               public function get mdct0():Mdct {
+                       return _mdct[0];
+               }
+       
+               public function get mdct1():Mdct {
+                       return _mdct[1];
+               }
+
+       }
+
+
 }
\ No newline at end of file
index 0f50452..a174a7b 100644 (file)
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import org.omtk.util.BitByteArray;\r
-       \r
-       public class Look {\r
-       \r
-               private var _map:int;\r
-               private var _parts:int;\r
-               private var _stages:int;\r
-               private var _fullbooks:Vector.<CodeBook>;\r
-               private var _phrasebook:CodeBook;\r
-               private var _partbooks:Vector.<Vector.<int>>;\r
-               private var _partvals:int;\r
-               private var _decodemap:Vector.<Vector.<int>>;\r
-               private var _postbits:int;\r
-               private var _phrasebits:int;\r
-               private var _frames:int;\r
-\r
-               public function Look(source:VorbisStream, residue:Residue, mode:Mode) {\r
-               \r
-                       var i:int;\r
-                       var j:int;\r
-                       var k:int;\r
-                       \r
-                       var dim:int = 0;\r
-                       var acc:int = 0;\r
-                       var maxstage:int = 0;\r
-\r
-                       _map = mode.mapping;\r
-                       \r
-                       _parts = residue.classifications;\r
-                       _fullbooks = source.setupHeader.codeBooks;\r
-                       _phrasebook = _fullbooks[residue.classBook];\r
-                       dim = _phrasebook.dimensions;\r
-\r
-                       _partbooks = new Vector.<Vector.<int>>(_parts);\r
-\r
-                       for (j = 0; j < _parts; j++) {\r
-                               var s:int = Util.ilog(residue.cascade[j]);\r
-                               if (s != 0) {\r
-                                       if (s > maxstage) {\r
-                                               maxstage = s;\r
-                                       }\r
-                                       _partbooks[j] = new Vector.<int>(s);\r
-                                       for (k = 0; k < s; k++) {\r
-                                               if ((residue.cascade[j] & (1 << k)) != 0) {\r
-                                                       _partbooks[j][k] = residue.books[j][k];\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-\r
-                       _partvals = Math.round(Math.pow(_parts, dim));\r
-                       _stages = maxstage;\r
-\r
-                       _decodemap = new Vector.<Vector.<int>>(_partvals, true);\r
-\r
-                       for (j = 0; j < _partvals; j++) {\r
-                               var val:int = j;\r
-                               var mult:int = _partvals / _parts;\r
-                               _decodemap[j] = new Vector.<int>(dim);\r
-\r
-                               for (k = 0; k < dim; k++) {\r
-                                       var deco:int = val / mult;\r
-                                       val -= deco * mult;\r
-                                       mult /= _parts;\r
-                                       _decodemap[j][k] = deco;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               public function get map():int {\r
-                       return _map;\r
-               }\r
-               \r
-               public function get parts():int {\r
-                       return _parts;\r
-               }\r
-               \r
-               public function get stages():int {\r
-                       return _stages;\r
-               }\r
-               \r
-               public function get fullbooks():Vector.<CodeBook> {\r
-                       return _fullbooks;\r
-               }\r
-               \r
-               public function get phrasebook():CodeBook {\r
-                       return _phrasebook;\r
-               }\r
-               \r
-               public function get partbooks():Vector.<Vector.<int>> {\r
-                       return _partbooks;\r
-               }\r
-               \r
-               public function get partvals():int {\r
-                       return _partvals;\r
-               }\r
-               \r
-               public function get decodemap():Vector.<Vector.<int>> {\r
-                       return _decodemap;\r
-               }\r
-               \r
-               public function get postbits():int {\r
-                       return _postbits;\r
-               }\r
-                       \r
-               public function get phrasebits():int {\r
-                       return _phrasebits;\r
-               }\r
-               \r
-               public function get frames():int {\r
-                       return _frames;\r
-               }\r
-                       \r
-       }\r
-       \r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import org.omtk.util.BitByteArray;
+       
+       public class Look {
+       
+               private var _map:int;
+               private var _parts:int;
+               private var _stages:int;
+               private var _fullbooks:Vector.<CodeBook>;
+               private var _phrasebook:CodeBook;
+               private var _partbooks:Vector.<Vector.<int>>;
+               private var _partvals:int;
+               private var _decodemap:Vector.<Vector.<int>>;
+               private var _postbits:int;
+               private var _phrasebits:int;
+               private var _frames:int;
+
+               public function Look(source:VorbisStream, residue:Residue, mode:Mode) {
+               
+                       var i:int;
+                       var j:int;
+                       var k:int;
+                       
+                       var dim:int = 0;
+                       var acc:int = 0;
+                       var maxstage:int = 0;
+
+                       _map = mode.mapping;
+                       
+                       _parts = residue.classifications;
+                       _fullbooks = source.setupHeader.codeBooks;
+                       _phrasebook = _fullbooks[residue.classBook];
+                       dim = _phrasebook.dimensions;
+
+                       _partbooks = new Vector.<Vector.<int>>(_parts);
+
+                       for (j = 0; j < _parts; j++) {
+                               var s:int = Util.ilog(residue.cascade[j]);
+                               if (s != 0) {
+                                       if (s > maxstage) {
+                                               maxstage = s;
+                                       }
+                                       _partbooks[j] = new Vector.<int>(s);
+                                       for (k = 0; k < s; k++) {
+                                               if ((residue.cascade[j] & (1 << k)) != 0) {
+                                                       _partbooks[j][k] = residue.books[j][k];
+                                               }
+                                       }
+                               }
+                       }
+
+                       _partvals = Math.round(Math.pow(_parts, dim));
+                       _stages = maxstage;
+
+                       _decodemap = new Vector.<Vector.<int>>(_partvals, true);
+
+                       for (j = 0; j < _partvals; j++) {
+                               var val:int = j;
+                               var mult:int = _partvals / _parts;
+                               _decodemap[j] = new Vector.<int>(dim);
+
+                               for (k = 0; k < dim; k++) {
+                                       var deco:int = val / mult;
+                                       val -= deco * mult;
+                                       mult /= _parts;
+                                       _decodemap[j][k] = deco;
+                               }
+                       }
+               }
+
+               public function get map():int {
+                       return _map;
+               }
+               
+               public function get parts():int {
+                       return _parts;
+               }
+               
+               public function get stages():int {
+                       return _stages;
+               }
+               
+               public function get fullbooks():Vector.<CodeBook> {
+                       return _fullbooks;
+               }
+               
+               public function get phrasebook():CodeBook {
+                       return _phrasebook;
+               }
+               
+               public function get partbooks():Vector.<Vector.<int>> {
+                       return _partbooks;
+               }
+               
+               public function get partvals():int {
+                       return _partvals;
+               }
+               
+               public function get decodemap():Vector.<Vector.<int>> {
+                       return _decodemap;
+               }
+               
+               public function get postbits():int {
+                       return _postbits;
+               }
+                       
+               public function get phrasebits():int {
+                       return _phrasebits;
+               }
+               
+               public function get frames():int {
+                       return _frames;
+               }
+                       
+       }
+       
 }
\ No newline at end of file
index 8b2c5ae..982bec7 100644 (file)
@@ -1,73 +1,73 @@
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import flash.errors.IllegalOperationError;\r
-       import org.omtk.util.BitByteArray;\r
-\r
-       public class Mapping {\r
-       \r
-               public static function createInstance(stream:VorbisStream, source:BitByteArray, header:SetupHeader):Mapping {\r
-               \r
-                       var type:int = source.readUnsignedBitwiseInt(16);\r
-                       switch (type) {\r
-                       case 0:\r
-                               return new Mapping0(stream, source, header);\r
-                       default:\r
-                               throw new Error("Mapping type " + type + " is not supported.");\r
-                       }\r
-               \r
-               }\r
-       \r
-               public function get type():int {\r
-                       throw new IllegalOperationError("not implemented");\r
-               }\r
-       \r
-               public function get couplingSteps():int {\r
-                       throw new IllegalOperationError("not implemented");\r
-               }\r
-\r
-               public function get submaps():int {\r
-                       throw new IllegalOperationError("not implemented");\r
-               }\r
-\r
-               public function get angles():Vector.<int> {\r
-                       throw new IllegalOperationError("not implemented");\r
-               }\r
-\r
-               public function get magnitudes():Vector.<int> {\r
-                       throw new IllegalOperationError("not implemented");\r
-               }\r
-\r
-               public function get mux():Vector.<int> {\r
-                       throw new IllegalOperationError("not implemented");\r
-               }\r
-\r
-               public function get submapFloors():Vector.<int> {\r
-                       throw new IllegalOperationError("not implemented");\r
-               }\r
-\r
-               public function get submapResidues():Vector.<int> {\r
-                       throw new IllegalOperationError("not implemented");\r
-               }\r
-\r
-       \r
-       }\r
-\r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import flash.errors.IllegalOperationError;
+       import org.omtk.util.BitByteArray;
+
+       public class Mapping {
+       
+               public static function createInstance(stream:VorbisStream, source:BitByteArray, header:SetupHeader):Mapping {
+               
+                       var type:int = source.readUnsignedBitwiseInt(16);
+                       switch (type) {
+                       case 0:
+                               return new Mapping0(stream, source, header);
+                       default:
+                               throw new Error("Mapping type " + type + " is not supported.");
+                       }
+               
+               }
+       
+               public function get type():int {
+                       throw new IllegalOperationError("not implemented");
+               }
+       
+               public function get couplingSteps():int {
+                       throw new IllegalOperationError("not implemented");
+               }
+
+               public function get submaps():int {
+                       throw new IllegalOperationError("not implemented");
+               }
+
+               public function get angles():Vector.<int> {
+                       throw new IllegalOperationError("not implemented");
+               }
+
+               public function get magnitudes():Vector.<int> {
+                       throw new IllegalOperationError("not implemented");
+               }
+
+               public function get mux():Vector.<int> {
+                       throw new IllegalOperationError("not implemented");
+               }
+
+               public function get submapFloors():Vector.<int> {
+                       throw new IllegalOperationError("not implemented");
+               }
+
+               public function get submapResidues():Vector.<int> {
+                       throw new IllegalOperationError("not implemented");
+               }
+
+       
+       }
+
 }
\ No newline at end of file
index 13dd013..547b533 100644 (file)
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import flash.errors.IllegalOperationError;\r
-       import org.omtk.util.BitByteArray;\r
-\r
-       public class Mapping0 extends Mapping {\r
-       \r
-               private var _magnitudes:Vector.<int>;\r
-               private var _angles:Vector.<int>;\r
-               private var _mux:Vector.<int>;\r
-               private var _submapFloors:Vector.<int>;\r
-               private var _submapResidues:Vector.<int>;\r
-       \r
-               public function Mapping0(stream:VorbisStream, source:BitByteArray, header:SetupHeader) {\r
-\r
-                       var i:int;\r
-                       var j:int;\r
-               \r
-                       var submaps:int = 1;\r
-       \r
-                       if (source.readBit()) {\r
-                               submaps = source.readUnsignedBitwiseInt(4) + 1;\r
-                       }\r
-       \r
-                       var channels:int = stream.identificationHeader.channels;\r
-                       var ilogChannels:int = Util.ilog(channels - 1);\r
-       \r
-                       if (source.readBit()) {\r
-                               var couplingSteps:int = source.readUnsignedBitwiseInt(8) + 1;\r
-                               _magnitudes = new Vector.<int>(couplingSteps);\r
-                               _angles = new Vector.<int>(couplingSteps);\r
-       \r
-                               for (i = 0; i < couplingSteps; i++) {\r
-                                       magnitudes[i] = source.readUnsignedBitwiseInt(ilogChannels);\r
-                                       angles[i] = source.readUnsignedBitwiseInt(ilogChannels);\r
-                                       if (magnitudes[i] == angles[i] || magnitudes[i] >= channels\r
-                                                       || angles[i] >= channels) {\r
-                                               throw new Error("The channel magnitude and/or angle mismatch.");\r
-                                       }\r
-                               }\r
-                       } else {\r
-                               _magnitudes = Vector.<int>([]);\r
-                               _angles = Vector.<int>([]);\r
-                       }\r
-       \r
-                       if (source.readUnsignedBitwiseInt(2) != 0) {\r
-                               throw new Error("A reserved mapping field has an invalid value.");\r
-                       }\r
-       \r
-                       _mux = new Vector.<int>(channels);\r
-                       if (submaps > 1) {\r
-                               for (i = 0; i < channels; i++) {\r
-                                       _mux[i] = source.readUnsignedBitwiseInt(4);\r
-                                       if (_mux[i] > submaps) {\r
-                                               throw new Error("A mapping mux value is higher than the number of submaps");\r
-                                       }\r
-                               }\r
-                       } else {\r
-                               for (i = 0; i < channels; i++) {\r
-                                       _mux[i] = 0;\r
-                               }\r
-                       }\r
-       \r
-                       _submapFloors = new Vector.<int>(submaps);\r
-                       _submapResidues = new Vector.<int>(submaps);\r
-       \r
-                       var floorCount:int = header.floors.length;\r
-                       var residueCount:int = header.residues.length;\r
-       \r
-                       for (i = 0; i < submaps; i++) {\r
-                               source.readUnsignedBitwiseInt(8); // discard time placeholder\r
-                               _submapFloors[i] = source.readUnsignedBitwiseInt(8);\r
-                               _submapResidues[i] = source.readUnsignedBitwiseInt(8);\r
-       \r
-                               if (_submapFloors[i] > floorCount) {\r
-                                       throw new Error("A mapping floor value is higher than the number of floors.");\r
-                               }\r
-       \r
-                               if (_submapResidues[i] > residueCount) {\r
-                                       throw new Error("A mapping residue value is higher than the number of residues.");\r
-                               }\r
-                       }\r
-               }\r
-       \r
-               public override function get type():int {\r
-                       return 0;\r
-               }\r
-       \r
-               public override function get couplingSteps():int {\r
-                       return _angles.length;\r
-               }\r
-\r
-               public override function get submaps():int {\r
-                       return _submapFloors.length;\r
-               }\r
-\r
-               public override function get angles():Vector.<int> {\r
-                       return _angles;\r
-               }\r
-\r
-               public override function get magnitudes():Vector.<int> {\r
-                       return _magnitudes;\r
-               }\r
-\r
-               public override function get mux():Vector.<int> {\r
-                       return _mux;\r
-               }\r
-\r
-               public override function get submapFloors():Vector.<int> {\r
-                       return _submapFloors;\r
-               }\r
-\r
-               public override function get submapResidues():Vector.<int> {\r
-                       return _submapResidues;\r
-               }       \r
-       }\r
-\r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import flash.errors.IllegalOperationError;
+       import org.omtk.util.BitByteArray;
+
+       public class Mapping0 extends Mapping {
+       
+               private var _magnitudes:Vector.<int>;
+               private var _angles:Vector.<int>;
+               private var _mux:Vector.<int>;
+               private var _submapFloors:Vector.<int>;
+               private var _submapResidues:Vector.<int>;
+       
+               public function Mapping0(stream:VorbisStream, source:BitByteArray, header:SetupHeader) {
+
+                       var i:int;
+                       var j:int;
+               
+                       var submaps:int = 1;
+       
+                       if (source.readBit()) {
+                               submaps = source.readUnsignedBitwiseInt(4) + 1;
+                       }
+       
+                       var channels:int = stream.identificationHeader.channels;
+                       var ilogChannels:int = Util.ilog(channels - 1);
+       
+                       if (source.readBit()) {
+                               var couplingSteps:int = source.readUnsignedBitwiseInt(8) + 1;
+                               _magnitudes = new Vector.<int>(couplingSteps);
+                               _angles = new Vector.<int>(couplingSteps);
+       
+                               for (i = 0; i < couplingSteps; i++) {
+                                       magnitudes[i] = source.readUnsignedBitwiseInt(ilogChannels);
+                                       angles[i] = source.readUnsignedBitwiseInt(ilogChannels);
+                                       if (magnitudes[i] == angles[i] || magnitudes[i] >= channels
+                                                       || angles[i] >= channels) {
+                                               throw new Error("The channel magnitude and/or angle mismatch.");
+                                       }
+                               }
+                       } else {
+                               _magnitudes = Vector.<int>([]);
+                               _angles = Vector.<int>([]);
+                       }
+       
+                       if (source.readUnsignedBitwiseInt(2) != 0) {
+                               throw new Error("A reserved mapping field has an invalid value.");
+                       }
+       
+                       _mux = new Vector.<int>(channels);
+                       if (submaps > 1) {
+                               for (i = 0; i < channels; i++) {
+                                       _mux[i] = source.readUnsignedBitwiseInt(4);
+                                       if (_mux[i] > submaps) {
+                                               throw new Error("A mapping mux value is higher than the number of submaps");
+                                       }
+                               }
+                       } else {
+                               for (i = 0; i < channels; i++) {
+                                       _mux[i] = 0;
+                               }
+                       }
+       
+                       _submapFloors = new Vector.<int>(submaps);
+                       _submapResidues = new Vector.<int>(submaps);
+       
+                       var floorCount:int = header.floors.length;
+                       var residueCount:int = header.residues.length;
+       
+                       for (i = 0; i < submaps; i++) {
+                               source.readUnsignedBitwiseInt(8); // discard time placeholder
+                               _submapFloors[i] = source.readUnsignedBitwiseInt(8);
+                               _submapResidues[i] = source.readUnsignedBitwiseInt(8);
+       
+                               if (_submapFloors[i] > floorCount) {
+                                       throw new Error("A mapping floor value is higher than the number of floors.");
+                               }
+       
+                               if (_submapResidues[i] > residueCount) {
+                                       throw new Error("A mapping residue value is higher than the number of residues.");
+                               }
+                       }
+               }
+       
+               public override function get type():int {
+                       return 0;
+               }
+       
+               public override function get couplingSteps():int {
+                       return _angles.length;
+               }
+
+               public override function get submaps():int {
+                       return _submapFloors.length;
+               }
+
+               public override function get angles():Vector.<int> {
+                       return _angles;
+               }
+
+               public override function get magnitudes():Vector.<int> {
+                       return _magnitudes;
+               }
+
+               public override function get mux():Vector.<int> {
+                       return _mux;
+               }
+
+               public override function get submapFloors():Vector.<int> {
+                       return _submapFloors;
+               }
+
+               public override function get submapResidues():Vector.<int> {
+                       return _submapResidues;
+               }       
+       }
+
 }
\ No newline at end of file
index 329c276..886deea 100644 (file)
@@ -1,62 +1,62 @@
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import flash.events.*;\r
-       import flash.system.*;\r
-       import flash.display.*;\r
-       import flash.net.*;\r
-       import flash.utils.getTimer;\r
-       \r
-       /*\r
-        * Wrapper for the haXe compiled class org.omtk.vorbis.MdctHX\r
-        */\r
-       public class Mdct {\r
-       \r
-               public static var initialized : Boolean = false;\r
-               private static var hxClass : Class;\r
-               \r
-               public static function initialize() : void {\r
-                       var ldr:Loader = new Loader();\r
-                       var swfUrl:String = "hxmdct.swf";\r
-                       var req:URLRequest = new URLRequest(swfUrl);\r
-                       var ldrContext:LoaderContext = \r
-                       new LoaderContext(false, ApplicationDomain.currentDomain);\r
-                       ldr.load(req, ldrContext);\r
-                       ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, swfLoaded);\r
-                       \r
-                       function swfLoaded(e:Event):void {\r
-                               hxClass = ApplicationDomain.currentDomain.getDefinition("org.omtk.vorbis.MdctHX") as Class;\r
-                               initialized = true;\r
-                       }               \r
-               }\r
-\r
-               private var delegate : Object;\r
-               \r
-               public function Mdct(n:int) { \r
-                       delegate = new hxClass(n);\r
-               }\r
-               \r
-               public function imdct(frq:Vector.<Number>, window:Vector.<Number>, pcm:Vector.<Number>):void {\r
-                       delegate.imdct(frq, window, pcm);\r
-               }\r
-\r
-       }\r
-               \r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import flash.events.*;
+       import flash.system.*;
+       import flash.display.*;
+       import flash.net.*;
+       import flash.utils.getTimer;
+       
+       /*
+        * Wrapper for the haXe compiled class org.omtk.vorbis.MdctHX
+        */
+       public class Mdct {
+       
+               public static var initialized : Boolean = false;
+               private static var hxClass : Class;
+               
+               public static function initialize() : void {
+                       var ldr:Loader = new Loader();
+                       var swfUrl:String = "hxmdct.swf";
+                       var req:URLRequest = new URLRequest(swfUrl);
+                       var ldrContext:LoaderContext = 
+                       new LoaderContext(false, ApplicationDomain.currentDomain);
+                       ldr.load(req, ldrContext);
+                       ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, swfLoaded);
+                       
+                       function swfLoaded(e:Event):void {
+                               hxClass = ApplicationDomain.currentDomain.getDefinition("org.omtk.vorbis.MdctHX") as Class;
+                               initialized = true;
+                       }               
+               }
+
+               private var delegate : Object;
+               
+               public function Mdct(n:int) { 
+                       delegate = new hxClass(n);
+               }
+               
+               public function imdct(frq:Vector.<Number>, window:Vector.<Number>, pcm:Vector.<Number>):void {
+                       delegate.imdct(frq, window, pcm);
+               }
+
+       }
+               
 }
\ No newline at end of file
index 6da6abf..cf27af2 100644 (file)
@@ -1,70 +1,70 @@
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import flash.errors.IllegalOperationError;\r
-       import flash.utils.Dictionary;\r
-       import org.omtk.util.BitByteArray;\r
-       \r
-       public class Mode\r
-       {\r
-               private var _blockFlag:Boolean;\r
-               private var _windowType:uint;\r
-               private var _transformType:uint;\r
-               private var _mapping:uint;\r
-               \r
-               public function Mode(source:BitByteArray, header:SetupHeader) {\r
-\r
-                       _blockFlag=source.readBit();\r
-                       _windowType=source.readUnsignedBitwiseInt(16);\r
-                       _transformType=source.readUnsignedBitwiseInt(16);\r
-                       _mapping=source.readUnsignedBitwiseInt(8);\r
-                       \r
-                       if(_windowType!=0) {\r
-                               throw new Error("Window type = "+windowType+", != 0");\r
-                       }\r
-                       \r
-                       if(_transformType!=0) {\r
-                               throw new Error("Transform type = "+transformType+", != 0");\r
-                       }\r
-                       \r
-                       if(_mapping > header.mappings.length) {\r
-                               throw new Error("Mode mapping number is higher than total number of mappings.");\r
-                       }\r
-               }\r
-       \r
-               public function get blockFlag():Boolean {\r
-                       return _blockFlag;\r
-               }\r
-               \r
-               public function get windowType():uint {\r
-                       return _windowType;\r
-               }\r
-               \r
-               public function get transformType():uint {\r
-                       return _transformType;\r
-               }\r
-               \r
-               public function get mapping():uint {\r
-                       return _mapping;\r
-               }\r
-       \r
-       }\r
-       \r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import flash.errors.IllegalOperationError;
+       import flash.utils.Dictionary;
+       import org.omtk.util.BitByteArray;
+       
+       public class Mode
+       {
+               private var _blockFlag:Boolean;
+               private var _windowType:uint;
+               private var _transformType:uint;
+               private var _mapping:uint;
+               
+               public function Mode(source:BitByteArray, header:SetupHeader) {
+
+                       _blockFlag=source.readBit();
+                       _windowType=source.readUnsignedBitwiseInt(16);
+                       _transformType=source.readUnsignedBitwiseInt(16);
+                       _mapping=source.readUnsignedBitwiseInt(8);
+                       
+                       if(_windowType!=0) {
+                               throw new Error("Window type = "+windowType+", != 0");
+                       }
+                       
+                       if(_transformType!=0) {
+                               throw new Error("Transform type = "+transformType+", != 0");
+                       }
+                       
+                       if(_mapping > header.mappings.length) {
+                               throw new Error("Mode mapping number is higher than total number of mappings.");
+                       }
+               }
+       
+               public function get blockFlag():Boolean {
+                       return _blockFlag;
+               }
+               
+               public function get windowType():uint {
+                       return _windowType;
+               }
+               
+               public function get transformType():uint {
+                       return _transformType;
+               }
+               
+               public function get mapping():uint {
+                       return _mapping;
+               }
+       
+       }
+       
 }
\ No newline at end of file
index 9c87ad9..de9924f 100644 (file)
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import flash.errors.IllegalOperationError;\r
-       import flash.utils.Dictionary;\r
-       import org.omtk.util.BitByteArray;\r
-       \r
-       public class Residue {\r
-\r
-               private var _begin:int;\r
-               private var _end:int;\r
-               private var _partitionSize:int;\r
-               private var _classifications:int;\r
-               private var _classBook:int;\r
-               private var _cascade:Vector.<int>;\r
-               private var _books:Vector.<Vector.<int>>;\r
-               \r
-               private var _looks:Dictionary;\r
-\r
-       \r
-               public function Residue(source:BitByteArray, header:SetupHeader) {\r
-\r
-                       _begin = source.readUnsignedBitwiseInt(24);\r
-                       _end = source.readUnsignedBitwiseInt(24);\r
-                       _partitionSize = source.readUnsignedBitwiseInt(24) + 1;\r
-                       _classifications = source.readUnsignedBitwiseInt(6) + 1;\r
-                       _classBook = source.readUnsignedBitwiseInt(8);\r
-       \r
-                       _cascade = new Vector.<int>(classifications);\r
-       \r
-                       var acc:int = 0;\r
-                       var i:int;\r
-                       var j:int;\r
-                       \r
-                       for (i = 0; i < classifications; i++) {\r
-                               var highBits:int = 0;\r
-                               var lowBits:int = 0;\r
-                               \r
-                               lowBits = source.readUnsignedBitwiseInt(3);\r
-                               if (source.readBit()) {\r
-                                       highBits = source.readUnsignedBitwiseInt(5);\r
-                               }\r
-                               _cascade[i] = (highBits << 3) | lowBits;\r
-                               acc += Util.icount(cascade[i]);\r
-                       }\r
-       \r
-                       _books = new Vector.<Vector.<int>>(classifications);\r
-       \r
-                       for (i = 0; i < classifications; i++) {\r
-                               books[i] = new Vector.<int>(8);\r
-                               for (j = 0; j < 8; j++) {\r
-                                       if ((cascade[i] & (1 << j)) != 0) {\r
-                                               books[i][j] = source.readUnsignedBitwiseInt(8);\r
-                                               if (books[i][j] > header.codeBooks.length) {\r
-                                                       throw new Error(\r
-                                                                       "Reference to invalid codebook entry in residue header.");\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-                       \r
-                       _looks = new Dictionary();\r
-               }\r
-       \r
-               public static function createInstance(source:BitByteArray, header:SetupHeader):Residue {\r
-       \r
-                       var type:int = source.readUnsignedBitwiseInt(16);\r
-                       switch (type) {\r
-                       case 2:\r
-                               return new Residue2(source, header);\r
-                       default:\r
-                               throw new Error("Residue type " + type + " is not supported.");\r
-                       }\r
-               }\r
-               \r
-               public function decodeResidue(\r
-                       vorbis:VorbisStream, source:BitByteArray, \r
-                       mode:Mode, ch:int,\r
-                       doNotDecodeFlags:Vector.<Boolean>, vectors0:Vector.<Number>, vectors1:Vector.<Number>):void {\r
-                               \r
-                       throw new IllegalOperationError("not implemented");\r
-               }\r
-               \r
-               \r
-               public function getLook(stream:VorbisStream, key:Mode):Look {\r
-                       var look:Look = _looks[key];\r
-                       if (look == null) {\r
-                               look = new Look(stream, this, key);\r
-                               _looks[key] = look;\r
-                       }\r
-                       return new Look(stream, this, key);//look;\r
-               }\r
-       \r
-       \r
-               public function get begin():int {\r
-                       return _begin;\r
-               }\r
-               \r
-               public function get end():int {\r
-                       return _end;\r
-               }\r
-               \r
-               public function get partitionSize():int {\r
-                       return _partitionSize;\r
-               }\r
-               \r
-               public function get classifications():int {\r
-                       return _classifications;\r
-               }\r
-               \r
-               public function get classBook():int {\r
-                       return _classBook;\r
-               }\r
-               \r
-               public function get cascade():Vector.<int> {\r
-                       return _cascade;\r
-               }\r
-               \r
-               public function get books():Vector.<Vector.<int>> {\r
-                       return _books;\r
-               }\r
-                       \r
-       }\r
-       \r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import flash.errors.IllegalOperationError;
+       import flash.utils.Dictionary;
+       import org.omtk.util.BitByteArray;
+       
+       public class Residue {
+
+               private var _begin:int;
+               private var _end:int;
+               private var _partitionSize:int;
+               private var _classifications:int;
+               private var _classBook:int;
+               private var _cascade:Vector.<int>;
+               private var _books:Vector.<Vector.<int>>;
+               
+               private var _looks:Dictionary;
+
+       
+               public function Residue(source:BitByteArray, header:SetupHeader) {
+
+                       _begin = source.readUnsignedBitwiseInt(24);
+                       _end = source.readUnsignedBitwiseInt(24);
+                       _partitionSize = source.readUnsignedBitwiseInt(24) + 1;
+                       _classifications = source.readUnsignedBitwiseInt(6) + 1;
+                       _classBook = source.readUnsignedBitwiseInt(8);
+       
+                       _cascade = new Vector.<int>(classifications);
+       
+                       var acc:int = 0;
+                       var i:int;
+                       var j:int;
+                       
+                       for (i = 0; i < classifications; i++) {
+                               var highBits:int = 0;
+                               var lowBits:int = 0;
+                               
+                               lowBits = source.readUnsignedBitwiseInt(3);
+                               if (source.readBit()) {
+                                       highBits = source.readUnsignedBitwiseInt(5);
+                               }
+                               _cascade[i] = (highBits << 3) | lowBits;
+                               acc += Util.icount(cascade[i]);
+                       }
+       
+                       _books = new Vector.<Vector.<int>>(classifications);
+       
+                       for (i = 0; i < classifications; i++) {
+                               books[i] = new Vector.<int>(8);
+                               for (j = 0; j < 8; j++) {
+                                       if ((cascade[i] & (1 << j)) != 0) {
+                                               books[i][j] = source.readUnsignedBitwiseInt(8);
+                                               if (books[i][j] > header.codeBooks.length) {
+                                                       throw new Error(
+                                                                       "Reference to invalid codebook entry in residue header.");
+                                               }
+                                       }
+                               }
+                       }
+                       
+                       _looks = new Dictionary();
+               }
+       
+               public static function createInstance(source:BitByteArray, header:SetupHeader):Residue {
+       
+                       var type:int = source.readUnsignedBitwiseInt(16);
+                       switch (type) {
+                       case 2:
+                               return new Residue2(source, header);
+                       default:
+                               throw new Error("Residue type " + type + " is not supported.");
+                       }
+               }
+               
+               public function decodeResidue(
+                       vorbis:VorbisStream, source:BitByteArray, 
+                       mode:Mode, ch:int,
+                       doNotDecodeFlags:Vector.<Boolean>, vectors0:Vector.<Number>, vectors1:Vector.<Number>):void {
+                               
+                       throw new IllegalOperationError("not implemented");
+               }
+               
+               
+               public function getLook(stream:VorbisStream, key:Mode):Look {
+                       var look:Look = _looks[key];
+                       if (look == null) {
+                               look = new Look(stream, this, key);
+                               _looks[key] = look;
+                       }
+                       return new Look(stream, this, key);//look;
+               }
+       
+       
+               public function get begin():int {
+                       return _begin;
+               }
+               
+               public function get end():int {
+                       return _end;
+               }
+               
+               public function get partitionSize():int {
+                       return _partitionSize;
+               }
+               
+               public function get classifications():int {
+                       return _classifications;
+               }
+               
+               public function get classBook():int {
+                       return _classBook;
+               }
+               
+               public function get cascade():Vector.<int> {
+                       return _cascade;
+               }
+               
+               public function get books():Vector.<Vector.<int>> {
+                       return _books;
+               }
+                       
+       }
+       
 }
\ No newline at end of file
index 7bec7c5..1fdc453 100644 (file)
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import flash.errors.IllegalOperationError;\r
-       import flash.utils.Dictionary;\r
-       import org.omtk.util.BitByteArray;\r
-\r
-       public class Residue2 extends Residue {\r
-       \r
-               public function Residue2(source:BitByteArray, header:SetupHeader) {\r
-                       super(source, header);\r
-               }\r
-\r
-               public override function decodeResidue(\r
-                       vorbis:VorbisStream, source:BitByteArray, \r
-                       mode:Mode, ch:int,\r
-                       doNotDecodeFlags:Vector.<Boolean>, vectors0:Vector.<Number>, vectors1:Vector.<Number>):void {\r
-\r
-                       var i:int;\r
-                       var j:int;\r
-                       var k:int;\r
-                       var l:int;\r
-                       var s:int;\r
-                       var slim:int;\r
-\r
-                       var look:Look = getLook(vorbis, mode);\r
-       \r
-                       var codeBook:CodeBook = vorbis.setupHeader.codeBooks[classBook];\r
-       \r
-                       var classvalsPerCodeword:int = codeBook.dimensions;\r
-                       var nToRead:int = end - begin;\r
-                       var partitionsToRead:int = nToRead / partitionSize; // partvals\r
-       \r
-                       var samplesPerPartition:int = partitionSize;\r
-                       var partitionsPerWord:int = look.phrasebook.dimensions;\r
-       \r
-                       var partWords:int = (partitionsToRead + partitionsPerWord - 1) / partitionsPerWord;\r
-       \r
-                       var offset:int;\r
-                       \r
-                       var left:Boolean = false;\r
-                       var right:Boolean = false;\r
-                       \r
-                       for (i = 0; i < doNotDecodeFlags.length; i++) {\r
-                               if (!doNotDecodeFlags[i]) {\r
-                                       if(i==0) {\r
-                                               left = true;\r
-                                       }\r
-                                       else if (i==1) {\r
-                                               right = true;\r
-                                       }\r
-                               }\r
-                       }\r
-       \r
-                       var partword:Array = new Array(partWords);\r
-                       \r
-                       var pb:int = source.position;\r
-                       \r
-                       slim = look.stages;\r
-                       for (s = 0; s < slim; s++) {\r
-                               \r
-                               for (i = 0, l = 0; i < partitionsToRead; l++) {\r
-                               \r
-                                       if (s == 0) {\r
-                                               var temp:int = source.readUnsignedHuffmanInt(look.phrasebook.huffmanRoot);\r
-                                               if (temp == -1) {\r
-                                                       throw new Error("Foo??");\r
-                                               }\r
-                                               partword[l] = look.decodemap[temp];\r
-                                               if (partword[l] == null) {\r
-                                                       throw new Error("Foo??");\r
-                                               }\r
-                                       }\r
-       \r
-                                       for (k = 0; k < partitionsPerWord && i < partitionsToRead; k++, i++) {\r
-                                               offset = begin + i * samplesPerPartition;\r
-\r
-                                               if ((cascade[partword[l][k]] & (1 << s)) != 0) {\r
-                                                       var stagebook:CodeBook = \r
-                                                               vorbis.setupHeader.codeBooks[look.partbooks[partword[l][k]][s]];\r
-                                                       if (stagebook != null) {\r
-                                                               stagebook.readVvAdd(vectors0, vectors1, left, right, source, offset, samplesPerPartition);\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-               \r
-               }\r
-               \r
-       }\r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import flash.errors.IllegalOperationError;
+       import flash.utils.Dictionary;
+       import org.omtk.util.BitByteArray;
+
+       public class Residue2 extends Residue {
+       
+               public function Residue2(source:BitByteArray, header:SetupHeader) {
+                       super(source, header);
+               }
+
+               public override function decodeResidue(
+                       vorbis:VorbisStream, source:BitByteArray, 
+                       mode:Mode, ch:int,
+                       doNotDecodeFlags:Vector.<Boolean>, vectors0:Vector.<Number>, vectors1:Vector.<Number>):void {
+
+                       var i:int;
+                       var j:int;
+                       var k:int;
+                       var l:int;
+                       var s:int;
+                       var slim:int;
+
+                       var look:Look = getLook(vorbis, mode);
+       
+                       var codeBook:CodeBook = vorbis.setupHeader.codeBooks[classBook];
+       
+                       var classvalsPerCodeword:int = codeBook.dimensions;
+                       var nToRead:int = end - begin;
+                       var partitionsToRead:int = nToRead / partitionSize; // partvals
+       
+                       var samplesPerPartition:int = partitionSize;
+                       var partitionsPerWord:int = look.phrasebook.dimensions;
+       
+                       var partWords:int = (partitionsToRead + partitionsPerWord - 1) / partitionsPerWord;
+       
+                       var offset:int;
+                       
+                       var left:Boolean = false;
+                       var right:Boolean = false;
+                       
+                       for (i = 0; i < doNotDecodeFlags.length; i++) {
+                               if (!doNotDecodeFlags[i]) {
+                                       if(i==0) {
+                                               left = true;
+                                       }
+                                       else if (i==1) {
+                                               right = true;
+                                       }
+                               }
+                       }
+       
+                       var partword:Array = new Array(partWords);
+                       
+                       var pb:int = source.position;
+                       
+                       slim = look.stages;
+                       for (s = 0; s < slim; s++) {
+                               
+                               for (i = 0, l = 0; i < partitionsToRead; l++) {
+                               
+                                       if (s == 0) {
+                                               var temp:int = source.readUnsignedHuffmanInt(look.phrasebook.huffmanRoot);
+                                               if (temp == -1) {
+                                                       throw new Error("Foo??");
+                                               }
+                                               partword[l] = look.decodemap[temp];
+                                               if (partword[l] == null) {
+                                                       throw new Error("Foo??");
+                                               }
+                                       }
+       
+                                       for (k = 0; k < partitionsPerWord && i < partitionsToRead; k++, i++) {
+                                               offset = begin + i * samplesPerPartition;
+
+                                               if ((cascade[partword[l][k]] & (1 << s)) != 0) {
+                                                       var stagebook:CodeBook = 
+                                                               vorbis.setupHeader.codeBooks[look.partbooks[partword[l][k]][s]];
+                                                       if (stagebook != null) {
+                                                               stagebook.readVvAdd(vectors0, vectors1, left, right, source, offset, samplesPerPartition);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               
+               }
+               
+       }
 }
\ No newline at end of file
index 885c182..1d1350f 100644 (file)
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import org.omtk.util.BitByteArray;\r
-\r
-       public class SetupHeader {\r
-       \r
-               private var _codeBooks:Vector.<CodeBook>;\r
-               private var _floors:Vector.<Floor>;\r
-               private var _residues:Vector.<Residue>;\r
-               private var _mappings:Vector.<Mapping>;\r
-               private var _modes:Vector.<Mode>;\r
-               \r
-               public function SetupHeader(stream:VorbisStream, source:BitByteArray) {\r
-\r
-                       var i:int;\r
-               \r
-                       source.readByte();\r
-                       source.readByte();\r
-                       source.readByte();\r
-                       source.readByte();\r
-                       source.readByte();\r
-                       source.readByte();\r
-       \r
-                       var codeBookCount:uint = source.readUnsignedBitwiseInt(8)+1;\r
-                       _codeBooks = new Vector.<CodeBook>(codeBookCount);\r
-                       \r
-                       for(i = 0; i < codeBookCount; i++) {\r
-                               _codeBooks[i] = new CodeBook(source);\r
-                       }\r
-                       \r
-                       // read the time domain transformations,\r
-                       // these should all be 0\r
-       \r
-                       var timeCount:int = source.readUnsignedBitwiseInt(6) + 1;\r
-                       for (i = 0; i < timeCount; i++) {\r
-                               if (source.readUnsignedBitwiseInt(16) != 0) {\r
-                                       throw new Error(\r
-                                                       "Time domain transformation != 0");\r
-                               }\r
-                       }\r
-                       \r
-                       // read floor entries\r
-       \r
-                       var floorCount:int = source.readUnsignedBitwiseInt(6) + 1;\r
-                       _floors = new Vector.<Floor>(floorCount);\r
-       \r
-                       for (i = 0; i < floorCount; i++) {\r
-                               _floors[i] = Floor.createInstance(source, this);\r
-                       }\r
-\r
-                       var residueCount:int = source.readUnsignedBitwiseInt(6) + 1;\r
-                       _residues = new Vector.<Residue>(residueCount);\r
-\r
-                       for (i = 0; i < residueCount; i++) {\r
-                               _residues[i] = Residue.createInstance(source, this);\r
-                       }\r
-                       \r
-                       var mappingCount:int = source.readUnsignedBitwiseInt(6) + 1;\r
-                       _mappings = new Vector.<Mapping>(mappingCount);\r
-       \r
-                       for (i = 0; i < mappingCount; i++) {\r
-                               _mappings[i] = Mapping.createInstance(stream, source, this);\r
-                       }\r
-                       \r
-                       var modeCount:int = source.readUnsignedBitwiseInt(6) + 1;\r
-                       _modes = new Vector.<Mode>(modeCount);\r
-       \r
-                       for (i = 0; i < modeCount; i++) {\r
-                               _modes[i] = new Mode(source, this);\r
-                       }\r
-       \r
-                       if (!source.readBit()) {\r
-                               throw new Error("The setup header framing bit is incorrect.");\r
-                       }\r
-               }\r
-       \r
-               public function get codeBooks():Vector.<CodeBook> {\r
-                       return _codeBooks;\r
-               }\r
-       \r
-               public function get floors():Vector.<Floor> {\r
-                       return _floors;\r
-               }\r
-\r
-               public function get mappings():Vector.<Mapping> {\r
-                       return _mappings;\r
-               }\r
-       \r
-               public function get residues():Vector.<Residue> {\r
-                       return _residues;\r
-               }\r
-\r
-               public function get modes():Vector.<Mode> {\r
-                       return _modes;\r
-               }\r
-               \r
-       }\r
-\r
-\r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import org.omtk.util.BitByteArray;
+
+       public class SetupHeader {
+       
+               private var _codeBooks:Vector.<CodeBook>;
+               private var _floors:Vector.<Floor>;
+               private var _residues:Vector.<Residue>;
+               private var _mappings:Vector.<Mapping>;
+               private var _modes:Vector.<Mode>;
+               
+               public function SetupHeader(stream:VorbisStream, source:BitByteArray) {
+
+                       var i:int;
+               
+                       source.readByte();
+                       source.readByte();
+                       source.readByte();
+                       source.readByte();
+                       source.readByte();
+                       source.readByte();
+       
+                       var codeBookCount:uint = source.readUnsignedBitwiseInt(8)+1;
+                       _codeBooks = new Vector.<CodeBook>(codeBookCount);
+                       
+                       for(i = 0; i < codeBookCount; i++) {
+                               _codeBooks[i] = new CodeBook(source);
+                       }
+                       
+                       // read the time domain transformations,
+                       // these should all be 0
+       
+                       var timeCount:int = source.readUnsignedBitwiseInt(6) + 1;
+                       for (i = 0; i < timeCount; i++) {
+                               if (source.readUnsignedBitwiseInt(16) != 0) {
+                                       throw new Error(
+                                                       "Time domain transformation != 0");
+                               }
+                       }
+                       
+                       // read floor entries
+       
+                       var floorCount:int = source.readUnsignedBitwiseInt(6) + 1;
+                       _floors = new Vector.<Floor>(floorCount);
+       
+                       for (i = 0; i < floorCount; i++) {
+                               _floors[i] = Floor.createInstance(source, this);
+                       }
+
+                       var residueCount:int = source.readUnsignedBitwiseInt(6) + 1;
+                       _residues = new Vector.<Residue>(residueCount);
+
+                       for (i = 0; i < residueCount; i++) {
+                               _residues[i] = Residue.createInstance(source, this);
+                       }
+                       
+                       var mappingCount:int = source.readUnsignedBitwiseInt(6) + 1;
+                       _mappings = new Vector.<Mapping>(mappingCount);
+       
+                       for (i = 0; i < mappingCount; i++) {
+                               _mappings[i] = Mapping.createInstance(stream, source, this);
+                       }
+                       
+                       var modeCount:int = source.readUnsignedBitwiseInt(6) + 1;
+                       _modes = new Vector.<Mode>(modeCount);
+       
+                       for (i = 0; i < modeCount; i++) {
+                               _modes[i] = new Mode(source, this);
+                       }
+       
+                       if (!source.readBit()) {
+                               throw new Error("The setup header framing bit is incorrect.");
+                       }
+               }
+       
+               public function get codeBooks():Vector.<CodeBook> {
+                       return _codeBooks;
+               }
+       
+               public function get floors():Vector.<Floor> {
+                       return _floors;
+               }
+
+               public function get mappings():Vector.<Mapping> {
+                       return _mappings;
+               }
+       
+               public function get residues():Vector.<Residue> {
+                       return _residues;
+               }
+
+               public function get modes():Vector.<Mode> {
+                       return _modes;
+               }
+               
+       }
+
+
 }
\ No newline at end of file
index 698f78b..f6e7ed1 100644 (file)
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       public class Util {\r
-\r
-               public static function ilog(x:uint):uint {\r
-                       var res:int = 0;\r
-                       for(; x>0; x>>=1, res++);\r
-                       return res;\r
-               }       \r
-               \r
-               public static function float32unpack(x:uint):Number {\r
-                       var mantissa:Number = x&0x1fffff;\r
-                       var e:Number = (x&0x7fe00000)>>21;\r
-                       if((x&0x80000000)!=0) {\r
-                               mantissa=-mantissa;\r
-                       }\r
-                       return mantissa*Math.pow(2.0, e-788.0);\r
-               }\r
-\r
-               public static function lookup1Values(a:int, b:int):uint {\r
-                       var res:uint = Math.pow(Math.E, Math.log(a)/b);\r
-                       return intPow(res+1, b)<=a?res+1:res;\r
-               }\r
-\r
-               public static function intPow(base:uint, e:uint):uint {\r
-                       var res:uint = 1;\r
-                       for(; e>0; e--, res*=base);\r
-                       return res;\r
-               }\r
-\r
-               public static function isBitSet(value:uint, bit:uint):Boolean {\r
-                       return (value&(1<<bit))!=0;\r
-               }\r
-               \r
-               public static function icount(value:uint):uint {\r
-                       var res:uint = 0;\r
-                       while (value > 0) {\r
-                               res += value & 1;\r
-                               value >>= 1;\r
-                       }\r
-                       return res;\r
-               }\r
-\r
-               public static function lowNeighbour(v:Vector.<int>, x:int):int {\r
-\r
-                       var max:int = -1;\r
-                       var n:int = 0;\r
-                       var i:int;\r
-                       \r
-                       for (i = 0; i < v.length && i < x; i++) {\r
-                               if (v[i] > max && v[i] < v[x]) {\r
-                                       max = v[i];\r
-                                       n = i;\r
-                               }\r
-                       }\r
-                       return n;\r
-               }\r
-\r
-               public static function highNeighbour(v:Vector.<int>, x:int):int {\r
-                       \r
-                       var min:int = int.MAX_VALUE;\r
-                       var n:int = 0;\r
-                       var i:int;\r
-                       \r
-                       for (i = 0; i < v.length && i < x; i++) {\r
-                               if (v[i] < min && v[i] > v[x]) {\r
-                                       min = v[i];\r
-                                       n = i;\r
-                               }\r
-                       }\r
-                       return n;\r
-               }\r
-\r
-               public static function renderPoint(x0:int, x1:int, y0:int, y1:int, x:int):int {\r
-                       return y0 + int(((y1-y0) * (x - x0)) / (x1 - x0));\r
-               }\r
-\r
-               public static function renderLine(x0:int, y0:int, x1:int, y1:int, v:Vector.<Number>):void {\r
-               \r
-                       var dy:int = y1 - y0;\r
-                       var adx:int = x1 - x0;\r
-                       var b:int = dy / adx;\r
-                       var sy:int = dy < 0 ? b - 1 : b + 1;\r
-                       var x:int = x0;\r
-                       var y:int = y0;\r
-                       var err:int = 0;\r
-                       var ady:int = (dy < 0 ? -dy : dy) - (b > 0 ? b * adx : -b * adx);\r
-       \r
-                       v[x] *= Floor.DB_STATIC_TABLE[y];\r
-                       for (x = x0 + 1; x < x1; x++) {\r
-                               err += ady;\r
-                               if (err >= adx) {\r
-                                       err -= adx;\r
-                                       v[x] *= Floor.DB_STATIC_TABLE[y += sy];\r
-                               } else {\r
-                                       v[x] *= Floor.DB_STATIC_TABLE[y += b];\r
-                               }\r
-                       }\r
-\r
-               }\r
-\r
-       }\r
-       \r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       public class Util {
+
+               public static function ilog(x:uint):uint {
+                       var res:int = 0;
+                       for(; x>0; x>>=1, res++);
+                       return res;
+               }       
+               
+               public static function float32unpack(x:uint):Number {
+                       var mantissa:Number = x&0x1fffff;
+                       var e:Number = (x&0x7fe00000)>>21;
+                       if((x&0x80000000)!=0) {
+                               mantissa=-mantissa;
+                       }
+                       return mantissa*Math.pow(2.0, e-788.0);
+               }
+
+               public static function lookup1Values(a:int, b:int):uint {
+                       var res:uint = Math.pow(Math.E, Math.log(a)/b);
+                       return intPow(res+1, b)<=a?res+1:res;
+               }
+
+               public static function intPow(base:uint, e:uint):uint {
+                       var res:uint = 1;
+                       for(; e>0; e--, res*=base);
+                       return res;
+               }
+
+               public static function isBitSet(value:uint, bit:uint):Boolean {
+                       return (value&(1<<bit))!=0;
+               }
+               
+               public static function icount(value:uint):uint {
+                       var res:uint = 0;
+                       while (value > 0) {
+                               res += value & 1;
+                               value >>= 1;
+                       }
+                       return res;
+               }
+
+               public static function lowNeighbour(v:Vector.<int>, x:int):int {
+
+                       var max:int = -1;
+                       var n:int = 0;
+                       var i:int;
+                       
+                       for (i = 0; i < v.length && i < x; i++) {
+                               if (v[i] > max && v[i] < v[x]) {
+                                       max = v[i];
+                                       n = i;
+                               }
+                       }
+                       return n;
+               }
+
+               public static function highNeighbour(v:Vector.<int>, x:int):int {
+                       
+                       var min:int = int.MAX_VALUE;
+                       var n:int = 0;
+                       var i:int;
+                       
+                       for (i = 0; i < v.length && i < x; i++) {
+                               if (v[i] < min && v[i] > v[x]) {
+                                       min = v[i];
+                                       n = i;
+                               }
+                       }
+                       return n;
+               }
+
+               public static function renderPoint(x0:int, x1:int, y0:int, y1:int, x:int):int {
+                       return y0 + int(((y1-y0) * (x - x0)) / (x1 - x0));
+               }
+
+               public static function renderLine(x0:int, y0:int, x1:int, y1:int, v:Vector.<Number>):void {
+               
+                       var dy:int = y1 - y0;
+                       var adx:int = x1 - x0;
+                       var b:int = dy / adx;
+                       var sy:int = dy < 0 ? b - 1 : b + 1;
+                       var x:int = x0;
+                       var y:int = y0;
+                       var err:int = 0;
+                       var ady:int = (dy < 0 ? -dy : dy) - (b > 0 ? b * adx : -b * adx);
+       
+                       v[x] *= Floor.DB_STATIC_TABLE[y];
+                       for (x = x0 + 1; x < x1; x++) {
+                               err += ady;
+                               if (err >= adx) {
+                                       err -= adx;
+                                       v[x] *= Floor.DB_STATIC_TABLE[y += sy];
+                               } else {
+                                       v[x] *= Floor.DB_STATIC_TABLE[y += b];
+                               }
+                       }
+
+               }
+
+       }
+       
 }
\ No newline at end of file
index 8a802f9..c82bb72 100644 (file)
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import flash.net.URLRequest;\r
-       import flash.net.URLStream;\r
-       import flash.utils.ByteArray;\r
-       import flash.utils.Endian;\r
-       import flash.events.Event;\r
-       import flash.events.ProgressEvent;\r
-       import flash.events.SampleDataEvent;\r
-       \r
-       import flash.external.ExternalInterface;\r
-\r
-       import flash.media.Sound;\r
-       \r
-       import org.omtk.ogg.UncachedUrlStream;\r
-       import org.omtk.ogg.EndOfOggStreamError;\r
-       import flash.utils.setTimeout;\r
-       \r
-       public class VorbisSound extends Sound {\r
-       \r
-               public static var METADATA_UPDATE: String = "metadata_update";\r
-       \r
-               private var urlStream: URLStream;\r
-               \r
-               private var oggStream:UncachedUrlStream;\r
-               private var vorbisStream:VorbisStream;\r
-\r
-               private var bytesAvailable:int;\r
-\r
-               private var initialized:Boolean = false;\r
-               private var playing:Boolean = false;\r
-               \r
-               private var fill1:Boolean = true;\r
-               private var fill2:Boolean = true;\r
-               \r
-               private var stopped: Boolean = false;\r
-               private var completeEventDispatched: Boolean = false;\r
-               \r
-               public function VorbisSound(url: URLRequest ) {\r
-                       urlStream = new URLStream();\r
-                       urlStream.endian = Endian.LITTLE_ENDIAN;\r
-                       urlStream.load(url);\r
-\r
-                       Mdct.initialize();\r
-\r
-                       oggStream = new UncachedUrlStream(urlStream);\r
-                       oggStream.addEventListener('progress', progress);\r
-                       bytesAvailable = oggStream.bytesAvailable;\r
-                       addEventListener("sampleData", sampleGenerator);\r
-               }\r
-               \r
-               private function initialize():void {\r
-                       vorbisStream = new VorbisStream(oggStream.getLogicalOggStream());\r
-                       setTimeout(dispatchEvent, 100, new Event(METADATA_UPDATE));\r
-                       initialized = true;\r
-               }\r
-               \r
-               private var samplesPlayed: int = 0;\r
-               \r
-               private function sampleGenerator(event:SampleDataEvent):void {\r
-                       \r
-                       if(stopped) {\r
-                               return;\r
-                       }\r
-                       \r
-                       if(Mdct.initialized && !initialized && bytesAvailable > 64*1024) {\r
-                               initialize();\r
-                       }\r
-                       \r
-                       if(initialized && bytesAvailable > 16*1024 && !vorbisStream.finished) {\r
-                               var cnt: int;\r
-                               cnt = vorbisStream.readPcm(event.data);\r
-                               samplesPlayed += cnt;\r
-                               if(cnt < 2048 && oggStream.bytesAvailable > 0) {\r
-                                       vorbisStream = new VorbisStream(oggStream.getLogicalOggStream());\r
-                                       setTimeout(dispatchEvent, 100, new Event(METADATA_UPDATE));\r
-                                       samplesPlayed += vorbisStream.readPcm(event.data);\r
-                               }\r
-                       }\r
-                       else if(vorbisStream == null || !vorbisStream.finished) {\r
-                           for(var c:int=0; c<2048; c++) {\r
-                               event.data.writeFloat(0);\r
-                               event.data.writeFloat(0);\r
-                           }\r
-                       }\r
-                       \r
-                       if(initialized && vorbisStream.finished && oggStream.bytesAvailable == 0 && !completeEventDispatched) {\r
-                               dispatchEvent(new Event(Event.COMPLETE));\r
-                               completeEventDispatched = true;\r
-                       }\r
-                       \r
-                       //trace("samples played: " + samplesPlayed + "/" + oggStream.bytesAvailable);\r
-                       \r
-               }\r
-\r
-               public function stop(): void {\r
-                       stopped = true;\r
-               }\r
-\r
-               public function progress(event:ProgressEvent):void {\r
-                       bytesAvailable = oggStream.bytesAvailable;\r
-               }\r
-\r
-               public function get position(): int {\r
-                       return samplesPlayed * 1000 / 44100;\r
-               }\r
-\r
-               public function getMetaData(key: String):String {\r
-                       if(vorbisStream != null) {\r
-                               return vorbisStream.commentHeader.comments[key];\r
-                       }\r
-                       else {\r
-                               return null;\r
-                       }\r
-               }\r
-       }\r
-       \r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import flash.net.URLRequest;
+       import flash.net.URLStream;
+       import flash.utils.ByteArray;
+       import flash.utils.Endian;
+       import flash.events.Event;
+       import flash.events.ProgressEvent;
+       import flash.events.SampleDataEvent;
+       
+       import flash.external.ExternalInterface;
+
+       import flash.media.Sound;
+       
+       import org.omtk.ogg.UncachedUrlStream;
+       import org.omtk.ogg.EndOfOggStreamError;
+       import flash.utils.setTimeout;
+       
+       public class VorbisSound extends Sound {
+       
+               public static var METADATA_UPDATE: String = "metadata_update";
+       
+               private var urlStream: URLStream;
+               
+               private var oggStream:UncachedUrlStream;
+               private var vorbisStream:VorbisStream;
+
+               private var bytesAvailable:int;
+
+               private var initialized:Boolean = false;
+               private var playing:Boolean = false;
+               
+               private var fill1:Boolean = true;
+               private var fill2:Boolean = true;
+               
+               private var stopped: Boolean = false;
+               private var completeEventDispatched: Boolean = false;
+               
+               public function VorbisSound(url: URLRequest ) {
+                       urlStream = new URLStream();
+                       urlStream.endian = Endian.LITTLE_ENDIAN;
+                       urlStream.load(url);
+
+                       Mdct.initialize();
+
+                       oggStream = new UncachedUrlStream(urlStream);
+                       oggStream.addEventListener('progress', progress);
+                       bytesAvailable = oggStream.bytesAvailable;
+                       addEventListener("sampleData", sampleGenerator);
+               }
+               
+               private function initialize():void {
+                       vorbisStream = new VorbisStream(oggStream.getLogicalOggStream());
+                       setTimeout(dispatchEvent, 100, new Event(METADATA_UPDATE));
+                       initialized = true;
+               }
+               
+               private var samplesPlayed: int = 0;
+               
+               private function sampleGenerator(event:SampleDataEvent):void {
+                       
+                       if(stopped) {
+                               return;
+                       }
+                       
+                       if(Mdct.initialized && !initialized && bytesAvailable > 64*1024) {
+                               initialize();
+                       }
+                       
+                       if(initialized && bytesAvailable > 16*1024 && !vorbisStream.finished) {
+                               var cnt: int;
+                               cnt = vorbisStream.readPcm(event.data);
+                               samplesPlayed += cnt;
+                               if(cnt < 2048 && oggStream.bytesAvailable > 0) {
+                                       vorbisStream = new VorbisStream(oggStream.getLogicalOggStream());
+                                       setTimeout(dispatchEvent, 100, new Event(METADATA_UPDATE));
+                                       samplesPlayed += vorbisStream.readPcm(event.data);
+                               }
+                       }
+                       else if(vorbisStream == null || !vorbisStream.finished) {
+                           for(var c:int=0; c<2048; c++) {
+                               event.data.writeFloat(0);
+                               event.data.writeFloat(0);
+                           }
+                       }
+                       
+                       if(initialized && vorbisStream.finished && oggStream.bytesAvailable == 0 && !completeEventDispatched) {
+                               dispatchEvent(new Event(Event.COMPLETE));
+                               completeEventDispatched = true;
+                       }
+                       
+                       //trace("samples played: " + samplesPlayed + "/" + oggStream.bytesAvailable);
+                       
+               }
+
+               public function stop(): void {
+                       stopped = true;
+               }
+
+               public function progress(event:ProgressEvent):void {
+                       bytesAvailable = oggStream.bytesAvailable;
+               }
+
+               public function get position(): int {
+                       return samplesPlayed * 1000 / 44100;
+               }
+
+               public function getMetaData(key: String):String {
+                       if(vorbisStream != null) {
+                               return vorbisStream.commentHeader.comments[key];
+                       }
+                       else {
+                               return null;
+                       }
+               }
+       }
+       
 }
\ No newline at end of file
index ea7a208..0c37fa1 100644 (file)
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis {\r
-\r
-       import flash.events.SampleDataEvent;\r
-       import flash.utils.ByteArray;\r
-       import flash.utils.Endian;\r
-       import org.omtk.util.*;\r
-       import org.omtk.ogg.*;\r
-       \r
-       public class VorbisStream {\r
-       \r
-               private const IDENTIFICATION_HEADER:int = 1;\r
-               private const COMMENT_HEADER:int = 3;\r
-               private const SETUP_HEADER:int = 5;\r
-               \r
-               private var source:LogicalOggStream;\r
-       \r
-               private var _identificationHeader:IdentificationHeader;\r
-               private var _commentHeader:CommentHeader;\r
-               private var _setupHeader:SetupHeader;\r
-               \r
-               private var _lastAudioPacket:AudioPacket;\r
-               \r
-               private var _currentGranulePosition:int=0;\r
-               private var packetCounter:int;\r
-               \r
-               private var _finished: Boolean = false;\r
-               \r
-               public var windows:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>(8);\r
-\r
-               public function VorbisStream(source:LogicalOggStream) {\r
-\r
-                       this.source = source;\r
-\r
-                       for (var i:int = 0; i < 3; i++) {\r
-\r
-                               var data:BitByteArray = source.getNextOggPacket().data;\r
-                               var headerType:int = data.readUnsignedByte();\r
-\r
-                               switch(headerType) {\r
-                               case IDENTIFICATION_HEADER:\r
-                                       _identificationHeader = new IdentificationHeader(data);\r
-                                       break;\r
-                               case COMMENT_HEADER:\r
-                                       _commentHeader = new CommentHeader(data);\r
-                                       break;\r
-                               case SETUP_HEADER:\r
-                                       _setupHeader = new SetupHeader(this, data);\r
-                                       break;\r
-                               }\r
-                       }\r
-                       \r
-               }\r
-       \r
-               public function get identificationHeader():IdentificationHeader {\r
-                       return _identificationHeader;\r
-               }\r
-               \r
-               public function get commentHeader():CommentHeader {\r
-                       return _commentHeader;\r
-               }\r
-               \r
-               public function get setupHeader():SetupHeader {\r
-                       return _setupHeader;\r
-               }\r
-       \r
-               public function readPcm(data:ByteArray): int {\r
-               \r
-                       var total:int;\r
-                       var i:int;\r
-                       \r
-                       if(_lastAudioPacket == null) {\r
-                               _lastAudioPacket = getNextAudioPacket();\r
-                       }\r
-\r
-                       total = 0;\r
-                       \r
-                       while(total < 2048 && !_finished) {\r
-                               try {\r
-                                       var ap:AudioPacket = getNextAudioPacket();\r
-                                       total += ap.readPcm(_lastAudioPacket, data);\r
-                                       _lastAudioPacket = ap;\r
-                               }\r
-                               catch(e: EndOfOggStreamError) {\r
-                                       // ok, stream finished\r
-                                       _finished = true;\r
-                               }\r
-                       }\r
-                                               \r
-                       return total;\r
-               }\r
-\r
-               private function getNextAudioPacket():AudioPacket {\r
-                       packetCounter++;\r
-                       var packet:OggPacket = source.getNextOggPacket();\r
-                       var res:AudioPacket = new AudioPacket(this, packet, _currentGranulePosition);\r
-                       if(_lastAudioPacket != null) {\r
-                               // don't count the first packet, since it doesn't contain any "real" samples\r
-                               _currentGranulePosition += res.numberOfSamples;\r
-                       }\r
-                       return res;\r
-               }       \r
-               \r
-               public function get finished() : Boolean {\r
-                       return _finished;\r
-               }\r
-               \r
-               public function get currentGranulePosition(): int {\r
-                       return _currentGranulePosition;\r
-               }\r
-       }\r
-       \r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis {
+
+       import flash.events.SampleDataEvent;
+       import flash.utils.ByteArray;
+       import flash.utils.Endian;
+       import org.omtk.util.*;
+       import org.omtk.ogg.*;
+       
+       public class VorbisStream {
+       
+               private const IDENTIFICATION_HEADER:int = 1;
+               private const COMMENT_HEADER:int = 3;
+               private const SETUP_HEADER:int = 5;
+               
+               private var source:LogicalOggStream;
+       
+               private var _identificationHeader:IdentificationHeader;
+               private var _commentHeader:CommentHeader;
+               private var _setupHeader:SetupHeader;
+               
+               private var _lastAudioPacket:AudioPacket;
+               
+               private var _currentGranulePosition:int=0;
+               private var packetCounter:int;
+               
+               private var _finished: Boolean = false;
+               
+               public var windows:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>(8);
+
+               public function VorbisStream(source:LogicalOggStream) {
+
+                       this.source = source;
+
+                       for (var i:int = 0; i < 3; i++) {
+
+                               var data:BitByteArray = source.getNextOggPacket().data;
+                               var headerType:int = data.readUnsignedByte();
+
+                               switch(headerType) {
+                               case IDENTIFICATION_HEADER:
+                                       _identificationHeader = new IdentificationHeader(data);
+                                       break;
+                               case COMMENT_HEADER:
+                                       _commentHeader = new CommentHeader(data);
+                                       break;
+                               case SETUP_HEADER:
+                                       _setupHeader = new SetupHeader(this, data);
+                                       break;
+                               }
+                       }
+                       
+               }
+       
+               public function get identificationHeader():IdentificationHeader {
+                       return _identificationHeader;
+               }
+               
+               public function get commentHeader():CommentHeader {
+                       return _commentHeader;
+               }
+               
+               public function get setupHeader():SetupHeader {
+                       return _setupHeader;
+               }
+       
+               public function readPcm(data:ByteArray): int {
+               
+                       var total:int;
+                       var i:int;
+                       
+                       if(_lastAudioPacket == null) {
+                               _lastAudioPacket = getNextAudioPacket();
+                       }
+
+                       total = 0;
+                       
+                       while(total < 2048 && !_finished) {
+                               try {
+                                       var ap:AudioPacket = getNextAudioPacket();
+                                       total += ap.readPcm(_lastAudioPacket, data);
+                                       _lastAudioPacket = ap;
+                               }
+                               catch(e: EndOfOggStreamError) {
+                                       // ok, stream finished
+                                       _finished = true;
+                               }
+                       }
+                                               
+                       return total;
+               }
+
+               private function getNextAudioPacket():AudioPacket {
+                       packetCounter++;
+                       var packet:OggPacket = source.getNextOggPacket();
+                       var res:AudioPacket = new AudioPacket(this, packet, _currentGranulePosition);
+                       if(_lastAudioPacket != null) {
+                               // don't count the first packet, since it doesn't contain any "real" samples
+                               _currentGranulePosition += res.numberOfSamples;
+                       }
+                       return res;
+               }       
+               
+               public function get finished() : Boolean {
+                       return _finished;
+               }
+               
+               public function get currentGranulePosition(): int {
+                       return _currentGranulePosition;
+               }
+       }
+       
 }
\ No newline at end of file
index a932a6f..4461c32 100644 (file)
-/*\r
-\r
-Copyright 2008 Tor-Einar Jarnbjo\r
-\r
-   Licensed under the Apache License, Version 2.0 (the "License");\r
-   you may not use this file except in compliance with the License.\r
-   You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-\r
-*/\r
-\r
-package org.omtk.vorbis;\r
-\r
-import flash.Vector;\r
-\r
-class MdctHX {\r
-\r
-       private static var cPI1_8:Float = 0.92387953251128675613;\r
-       private static var cPI2_8:Float = 0.70710678118654752441;\r
-       private static var cPI3_8:Float = 0.38268343236508977175;\r
-       \r
-       private var n:Int;\r
-       private var log2n:Int;\r
-       private var trig:Vector<Float>;\r
-       private var bitrev:Vector<Int>;\r
-       \r
-       private var dtmp1:Float;\r
-       private var dtmp2:Float;\r
-       private var dtmp3:Float;\r
-       private var dtmp4:Float;\r
-\r
-       private var x:Vector<Float>;\r
-       private var w:Vector<Float>;\r
-\r
-       public function new(n:Int) { \r
-               this.n = n;\r
-       \r
-               var i:Int;\r
-               var j:Int;\r
-               \r
-               bitrev = new Vector<Int>();\r
-               trig = new Vector<Float>(Std.int(n+n/4), true);\r
-\r
-               for(i in 0...Std.int(n+n/4)) {\r
-                       trig[i] = 0;\r
-               }\r
-\r
-               x = new Vector<Float>(Std.int(n/2), true);\r
-               w = new Vector<Float>(Std.int(n/2), true);\r
-\r
-               for(i in 0...Std.int(n/2)) {\r
-                       x[i] = 0;\r
-                       w[i] = 0;\r
-               }\r
-               \r
-               var n2:Int = n >>> 1;\r
-               log2n = Math.round(Math.log(n) / Math.log(2));\r
-\r
-               var AE:Int = 0;\r
-               var AO:Int = 1;\r
-               var BE:Int = Std.int(AE + n / 2);\r
-               var BO:Int = BE + 1;\r
-               var CE:Int = Std.int(BE + n / 2);\r
-               var CO:Int = CE + 1;\r
-               \r
-               for (i in 0...Std.int(n/4)) {\r
-                       trig[AE + i * 2] = Math.cos((Math.PI / n) * (4 * i));\r
-                       trig[AO + i * 2] = -Math.sin((Math.PI / n) * (4 * i));\r
-                       trig[BE + i * 2] = Math.cos((Math.PI / (2 * n)) * (2 * i + 1));\r
-                       trig[BO + i * 2] = Math.sin((Math.PI / (2 * n)) * (2 * i + 1));\r
-               }\r
-\r
-               for (i in 0...Std.int(n/8)) {\r
-                       trig[CE + i * 2] = Math.cos((Math.PI / n) * (4 * i + 2));\r
-                       trig[CO + i * 2] = -Math.sin((Math.PI / n) * (4 * i + 2));\r
-               }\r
-               \r
-               var mask:Int = (1 << (log2n - 1)) - 1;\r
-               var msb:Int = 1 << (log2n - 2);\r
-               \r
-               for (i in 0...Std.int(n/8)) {\r
-                       var acc:Int = 0;\r
-                       j = 0;\r
-                       while(msb>>>j!=0) {\r
-                               if (((msb >>> j) & i) != 0) {\r
-                                       acc |= 1 << j;\r
-                               }\r
-                               j++;\r
-                       }\r
-                       bitrev[i * 2] = ((~acc) & mask);\r
-                       bitrev[i * 2 + 1] = acc;\r
-               }\r
-               \r
-       } \r
-\r
-       public function imdct(frq:Vector<Float>, window:Vector<Float>, pcm:Vector<Float>):Void {\r
-       \r
-               var i:Int;\r
-\r
-               var n2:Int;\r
-               var n4:Int;\r
-               var n8:Int;\r
-\r
-               var inO:Int;\r
-               var xO:Int;\r
-               var A:Int;\r
-\r
-               var temp1:Float;\r
-               var temp2:Float;\r
-\r
-               var B:Int;\r
-               var o1:Int;\r
-               var o2:Int;\r
-               var o3:Int;\r
-               var o4:Int;\r
-\r
-               var xx:Int;\r
-               var xxx:Vector<Float>;\r
-               \r
-               n2 = n >> 1;\r
-               n4 = n >> 2;\r
-               n8 = n >> 3;\r
-\r
-               inO = -1;\r
-               xO = 0;\r
-               A = n2;\r
-               \r
-               temp1 = 0.0;\r
-               temp2 = 0.0;\r
-               \r
-               for (i in 0...n8) {\r
-                       dtmp1 = frq[inO += 2];\r
-                       dtmp2 = frq[inO += 2];\r
-                       dtmp3 = trig[--A];\r
-                       dtmp4 = trig[--A];\r
-                       x[xO++] = -dtmp2 * dtmp3 - dtmp1 * dtmp4;\r
-                       x[xO++] = dtmp1 * dtmp3 - dtmp2 * dtmp4;\r
-               }\r
-\r
-               inO = n2;\r
-\r
-               for(i in 0...n8) {\r
-                       dtmp1 = frq[inO -= 2];\r
-                       dtmp2 = frq[inO -= 2];\r
-                       dtmp3 = trig[--A];\r
-                       dtmp4 = trig[--A];\r
-                       x[xO++] = dtmp2 * dtmp3 + dtmp1 * dtmp4;\r
-                       x[xO++] = dtmp2 * dtmp4 - dtmp1 * dtmp3;\r
-               }\r
-\r
-               xxx = kernel(x, w, n, n2, n4, n8);\r
-               xx = 0;\r
-               \r
-               B = n2;\r
-               o1 = n4;\r
-               o2 = o1 - 1;\r
-               o3 = n4 + n2;\r
-               o4 = o3 - 1;\r
-\r
-               for (i in 0...n4) {\r
-                       dtmp1 = xxx[xx++];\r
-                       dtmp2 = xxx[xx++];\r
-                       dtmp3 = trig[B++];\r
-                       dtmp4 = trig[B++];\r
-\r
-                       temp1 = (dtmp1 * dtmp4 - dtmp2 * dtmp3);\r
-                       temp2 = -(dtmp1 * dtmp3 + dtmp2 * dtmp4);\r
-\r
-                       pcm[o1] = -temp1 * window[o1];\r
-                       pcm[o2] = temp1 * window[o2];\r
-                       pcm[o3] = temp2 * window[o3];\r
-                       pcm[o4] = temp2 * window[o4];\r
-\r
-                       o1++;\r
-                       o2--;\r
-                       o3++;\r
-                       o4--;\r
-               }\r
-               \r
-       }\r
-\r
-       private inline function kernel(x:Vector<Float>, w:Vector<Float>, n:Int, n2:Int, n4:Int, n8:Int):Vector<Float> {\r
-\r
-               var i:Int;\r
-               var r:Int;\r
-               var s:Int;\r
-               var rlim:Int;\r
-               var slim:Int;\r
-               \r
-               var xA:Int = n4;\r
-               var xB:Int = 0;\r
-               var w1:Int = 0;\r
-               var w2:Int = n4;\r
-               var A:Int = n2;\r
-\r
-               var x0:Float;\r
-               var x1:Float;\r
-               var wA:Float;\r
-               var wB:Float;\r
-               var wC:Float;\r
-               var wD:Float;\r
-               var k0:Int;\r
-               var k1:Int;\r
-               var t1:Int;\r
-               var t2:Int;\r
-               \r
-               var wbase:Int;\r
-               var temp:Vector<Float>;\r
-               \r
-               var wACE:Float;\r
-               var wBCE:Float;\r
-               var wACO:Float;\r
-               var wBCO:Float;\r
-                       \r
-               var AEv:Float;\r
-               var AOv:Float;\r
-                       \r
-               i=0;\r
-               while(i < n4) {\r
-                       x0 = x[xA] - x[xB];\r
-                       \r
-                       w[w2 + i] = x[xA++] + x[xB++];\r
-\r
-                       x1 = x[xA] - x[xB];\r
-                       A -= 4;\r
-\r
-                       w[i++] = x0 * trig[A] + x1 * trig[A + 1];\r
-                       w[i] = x1 * trig[A] - x0 * trig[A + 1];\r
-\r
-                       w[w2 + i] = x[xA++] + x[xB++];\r
-                       i++;\r
-               }\r
-\r
-               for (i in 0...log2n-3) {\r
-                       k0 = n >>> (i + 2);\r
-                       k1 = 1 << (i + 3);\r
-                       wbase = n2 - 2;\r
-\r
-                       A = 0;\r
-\r
-                       rlim = k0 >>> 2;\r
-                       for (r in 0...rlim) {\r
-                       \r
-                               w1 = wbase;\r
-                               w2 = w1 - (k0 >> 1);\r
-                               AEv = trig[A];\r
-                               AOv = trig[A + 1];\r
-                               wbase -= 2;\r
-\r
-                               k0++;\r
-                               \r
-                               slim = 2 << i;\r
-                               for (s in 0...slim) {\r
-                                       dtmp1 = w[w1];\r
-                                       dtmp2 = w[w2];\r
-                                       wB = dtmp1 - dtmp2;\r
-                                       x[w1] = dtmp1 + dtmp2;\r
-                                       dtmp1 = w[++w1];\r
-                                       dtmp2 = w[++w2];\r
-                                       wA = dtmp1 - dtmp2;\r
-                                       x[w1] = dtmp1 + dtmp2;\r
-                                       x[w2] = wA * AEv - wB * AOv;\r
-                                       x[w2-1] = wB * AEv + wA * AOv;\r
-                                       w1 -= k0;\r
-                                       w2 -= k0;\r
-                               }\r
-                               k0--;\r
-                               A += k1;\r
-                       }\r
-\r
-                       temp = w;\r
-                       w = x;\r
-                       x = temp;\r
-               }\r
-               \r
-\r
-               var C:Int = n;\r
-               var bit:Int = 0;\r
-               var xx1:Int = 0;\r
-               var xx2:Int = n2 - 1;\r
-               \r
-               var wt1: Float;\r
-               var wt2: Float;\r
-               var wt12: Float;\r
-               var wt21: Float;\r
-               var trigV: Float;\r
-\r
-               for (i in 0...n8) {\r
-                       t1 = bitrev[bit++];\r
-                       t2 = bitrev[bit++];\r
-                       \r
-                       wt1 = w[t1];\r
-                       wt2 = w[t2];\r
-                       wt12 = w[t1-1];\r
-                       wt21 = w[t2+1];\r
-\r
-                       wA = wt1 - wt21;\r
-                       wB = wt12 + wt2;\r
-                       wC = wt1 + wt21;\r
-                       wD = wt12 - wt2;\r
-                       \r
-                       trigV = trig[C];\r
-\r
-                       wACE = wA * trigV;\r
-                       wBCE = wB * trigV;\r
-                       \r
-                       trigV = trig[++C];\r
-                       \r
-                       wACO = wA * trigV;\r
-                       wBCO = wB * trigV;\r
-                       \r
-                       ++C;\r
-\r
-                       x[xx1++] = (wC + wACO + wBCE);\r
-                       x[xx2--] = (-wD + wBCO - wACE);\r
-                       x[xx1++] = (wD + wBCO - wACE);\r
-                       x[xx2--] = (wC - wACO - wBCE);\r
-               }\r
-\r
-               return x;\r
-       }       \r
-\r
-       /*\r
-        * Dummy function required for the haXe compiler to build this to\r
-        * a .SWF file.\r
-        */\r
-       public static function main() : Void {  \r
-       }\r
-       \r
-}\r
+/*
+
+Copyright 2008 Tor-Einar Jarnbjo
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+*/
+
+package org.omtk.vorbis;
+
+import flash.Vector;
+
+class MdctHX {
+
+       private static var cPI1_8:Float = 0.92387953251128675613;
+       private static var cPI2_8:Float = 0.70710678118654752441;
+       private static var cPI3_8:Float = 0.38268343236508977175;
+       
+       private var n:Int;
+       private var log2n:Int;
+       private var trig:Vector<Float>;
+       private var bitrev:Vector<Int>;
+       
+       private var dtmp1:Float;
+       private var dtmp2:Float;
+       private var dtmp3:Float;
+       private var dtmp4:Float;
+
+       private var x:Vector<Float>;
+       private var w:Vector<Float>;
+
+       public function new(n:Int) { 
+               this.n = n;
+       
+               var i:Int;
+               var j:Int;
+               
+               bitrev = new Vector<Int>();
+               trig = new Vector<Float>(Std.int(n+n/4), true);
+
+               for(i in 0...Std.int(n+n/4)) {
+                       trig[i] = 0;
+               }
+
+               x = new Vector<Float>(Std.int(n/2), true);
+               w = new Vector<Float>(Std.int(n/2), true);
+
+               for(i in 0...Std.int(n/2)) {
+                       x[i] = 0;
+                       w[i] = 0;
+               }
+               
+               var n2:Int = n >>> 1;
+               log2n = Math.round(Math.log(n) / Math.log(2));
+
+               var AE:Int = 0;
+               var AO:Int = 1;
+               var BE:Int = Std.int(AE + n / 2);
+               var BO:Int = BE + 1;
+               var CE:Int = Std.int(BE + n / 2);
+               var CO:Int = CE + 1;
+               
+               for (i in 0...Std.int(n/4)) {
+                       trig[AE + i * 2] = Math.cos((Math.PI / n) * (4 * i));
+                       trig[AO + i * 2] = -Math.sin((Math.PI / n) * (4 * i));
+                       trig[BE + i * 2] = Math.cos((Math.PI / (2 * n)) * (2 * i + 1));
+                       trig[BO + i * 2] = Math.sin((Math.PI / (2 * n)) * (2 * i + 1));
+               }
+
+               for (i in 0...Std.int(n/8)) {
+                       trig[CE + i * 2] = Math.cos((Math.PI / n) * (4 * i + 2));
+                       trig[CO + i * 2] = -Math.sin((Math.PI / n) * (4 * i + 2));
+               }
+               
+               var mask:Int = (1 << (log2n - 1)) - 1;
+               var msb:Int = 1 << (log2n - 2);
+               
+               for (i in 0...Std.int(n/8)) {
+                       var acc:Int = 0;
+                       j = 0;
+                       while(msb>>>j!=0) {
+                               if (((msb >>> j) & i) != 0) {
+                                       acc |= 1 << j;
+                               }
+                               j++;
+                       }
+                       bitrev[i * 2] = ((~acc) & mask);
+                       bitrev[i * 2 + 1] = acc;
+               }
+               
+       } 
+
+       public function imdct(frq:Vector<Float>, window:Vector<Float>, pcm:Vector<Float>):Void {
+       
+               var i:Int;
+
+               var n2:Int;
+               var n4:Int;
+               var n8:Int;
+
+               var inO:Int;
+               var xO:Int;
+               var A:Int;
+
+               var temp1:Float;
+               var temp2:Float;
+
+               var B:Int;
+               var o1:Int;
+               var o2:Int;
+               var o3:Int;
+               var o4:Int;
+
+               var xx:Int;
+               var xxx:Vector<Float>;
+               
+               n2 = n >> 1;
+               n4 = n >> 2;
+               n8 = n >> 3;
+
+               inO = -1;
+               xO = 0;
+               A = n2;
+               
+               temp1 = 0.0;
+               temp2 = 0.0;
+               
+               for (i in 0...n8) {
+                       dtmp1 = frq[inO += 2];
+                       dtmp2 = frq[inO += 2];
+                       dtmp3 = trig[--A];
+                       dtmp4 = trig[--A];
+                       x[xO++] = -dtmp2 * dtmp3 - dtmp1 * dtmp4;
+                       x[xO++] = dtmp1 * dtmp3 - dtmp2 * dtmp4;
+               }
+
+               inO = n2;
+
+               for(i in 0...n8) {
+                       dtmp1 = frq[inO -= 2];
+                       dtmp2 = frq[inO -= 2];
+                       dtmp3 = trig[--A];
+                       dtmp4 = trig[--A];
+                       x[xO++] = dtmp2 * dtmp3 + dtmp1 * dtmp4;
+                       x[xO++] = dtmp2 * dtmp4 - dtmp1 * dtmp3;
+               }
+
+               xxx = kernel(x, w, n, n2, n4, n8);
+               xx = 0;
+               
+               B = n2;
+               o1 = n4;
+               o2 = o1 - 1;
+               o3 = n4 + n2;
+               o4 = o3 - 1;
+
+               for (i in 0...n4) {
+                       dtmp1 = xxx[xx++];
+                       dtmp2 = xxx[xx++];
+                       dtmp3 = trig[B++];
+                       dtmp4 = trig[B++];
+
+                       temp1 = (dtmp1 * dtmp4 - dtmp2 * dtmp3);
+                       temp2 = -(dtmp1 * dtmp3 + dtmp2 * dtmp4);
+
+                       pcm[o1] = -temp1 * window[o1];
+                       pcm[o2] = temp1 * window[o2];
+                       pcm[o3] = temp2 * window[o3];
+                       pcm[o4] = temp2 * window[o4];
+
+                       o1++;
+                       o2--;
+                       o3++;
+                       o4--;
+               }
+               
+       }
+
+       private inline function kernel(x:Vector<Float>, w:Vector<Float>, n:Int, n2:Int, n4:Int, n8:Int):Vector<Float> {
+
+               var i:Int;
+               var r:Int;
+               var s:Int;
+               var rlim:Int;
+               var slim:Int;
+               
+               var xA:Int = n4;
+               var xB:Int = 0;
+               var w1:Int = 0;
+               var w2:Int = n4;
+               var A:Int = n2;
+
+               var x0:Float;
+               var x1:Float;
+               var wA:Float;
+               var wB:Float;
+               var wC:Float;
+               var wD:Float;
+               var k0:Int;
+               var k1:Int;
+               var t1:Int;
+               var t2:Int;
+               
+               var wbase:Int;
+               var temp:Vector<Float>;
+               
+               var wACE:Float;
+               var wBCE:Float;
+               var wACO:Float;
+               var wBCO:Float;
+                       
+               var AEv:Float;
+               var AOv:Float;
+                       
+               i=0;
+               while(i < n4) {
+                       x0 = x[xA] - x[xB];
+                       
+                       w[w2 + i] = x[xA++] + x[xB++];
+
+                       x1 = x[xA] - x[xB];
+                       A -= 4;
+
+                       w[i++] = x0 * trig[A] + x1 * trig[A + 1];
+                       w[i] = x1 * trig[A] - x0 * trig[A + 1];
+
+                       w[w2 + i] = x[xA++] + x[xB++];
+                       i++;
+               }
+
+               for (i in 0...log2n-3) {
+                       k0 = n >>> (i + 2);
+                       k1 = 1 << (i + 3);
+                       wbase = n2 - 2;
+
+                       A = 0;
+
+                       rlim = k0 >>> 2;
+                       for (r in 0...rlim) {
+                       
+                               w1 = wbase;
+                               w2 = w1 - (k0 >> 1);
+                               AEv = trig[A];
+                               AOv = trig[A + 1];
+                               wbase -= 2;
+
+                               k0++;
+                               
+                               slim = 2 << i;
+                               for (s in 0...slim) {
+                                       dtmp1 = w[w1];
+                                       dtmp2 = w[w2];
+                                       wB = dtmp1 - dtmp2;
+                                       x[w1] = dtmp1 + dtmp2;
+                                       dtmp1 = w[++w1];
+                                       dtmp2 = w[++w2];
+                                       wA = dtmp1 - dtmp2;
+                                       x[w1] = dtmp1 + dtmp2;
+                                       x[w2] = wA * AEv - wB * AOv;
+                                       x[w2-1] = wB * AEv + wA * AOv;
+                                       w1 -= k0;
+                                       w2 -= k0;
+                               }
+                               k0--;
+                               A += k1;
+                       }
+
+                       temp = w;
+                       w = x;
+                       x = temp;
+               }
+               
+
+               var C:Int = n;
+               var bit:Int = 0;
+               var xx1:Int = 0;
+               var xx2:Int = n2 - 1;
+               
+               var wt1: Float;
+               var wt2: Float;
+               var wt12: Float;
+               var wt21: Float;
+               var trigV: Float;
+
+               for (i in 0...n8) {
+                       t1 = bitrev[bit++];
+                       t2 = bitrev[bit++];
+                       
+                       wt1 = w[t1];
+                       wt2 = w[t2];
+                       wt12 = w[t1-1];
+                       wt21 = w[t2+1];
+
+                       wA = wt1 - wt21;
+                       wB = wt12 + wt2;
+                       wC = wt1 + wt21;
+                       wD = wt12 - wt2;
+                       
+                       trigV = trig[C];
+
+                       wACE = wA * trigV;
+                       wBCE = wB * trigV;
+                       
+                       trigV = trig[++C];
+                       
+                       wACO = wA * trigV;
+                       wBCO = wB * trigV;
+                       
+                       ++C;
+
+                       x[xx1++] = (wC + wACO + wBCE);
+                       x[xx2--] = (-wD + wBCO - wACE);
+                       x[xx1++] = (wD + wBCO - wACE);
+                       x[xx2--] = (wC - wACO - wBCE);
+               }
+
+               return x;
+       }       
+
+       /*
+        * Dummy function required for the haXe compiler to build this to
+        * a .SWF file.
+        */
+       public static function main() : Void {  
+       }
+       
+}
index 3afc899..734c4bf 100644 (file)
-1\r
-00:00:01,080 --> 00:00:09,078\r
-片名:鐵扇公主\r
-\r
-2\r
-00:02:03,119 --> 00:02:09,280\r
-西遊記,本為一部絕妙之童話\r
-\r
-3\r
-00:02:09,280 --> 00:02:15,280\r
-特以世多誤解,致被目為神怪小說\r
-\r
-4\r
-00:02:15,280 --> 00:02:19,240\r
-本片取材於是\r
-\r
-5\r
-00:02:19,240 --> 00:02:24,240\r
-實為培育兒童心理而作\r
-\r
-6\r
-00:02:24,240 --> 00:02:29,280\r
-故內容刪蕪存精,不涉神怪\r
-\r
-7\r
-00:02:29,280 --> 00:02:32,560\r
-僅以唐僧等四人路阻火焰山\r
-\r
-8\r
-00:02:32,560 --> 00:02:41,040\r
-以示人生途徑中之磨難\r
-\r
-9\r
-00:02:41,040 --> 00:02:46,440\r
-欲求經此磨難,則必須堅持信念\r
-大眾一心\r
-\r
-10\r
-00:02:46,440 --> 00:02:52,436\r
-始能獲得此撲滅凶焰之芭蕉扇\r
-\r
-11\r
-00:03:34,480 --> 00:03:37,790\r
-現在已經秋天了,怎麼還這麼熱\r
-\r
-12\r
-00:03:37,840 --> 00:03:42,356\r
-呆子,不要說廢話,趕路要緊\r
-\r
-13\r
-00:04:06,920 --> 00:04:09,354\r
-悟空,這是到了什麼地方\r
-\r
-14\r
-00:04:09,400 --> 00:04:13,678\r
-反正是我們上西天必定要經過的地方\r
-\r
-15\r
-00:04:13,720 --> 00:04:18,111\r
-我們沒有走錯路線吧\r
-\r
-16\r
-00:04:18,159 --> 00:04:22,311\r
-為什麼這個地方這麼樣的熱呢\r
-\r
-17\r
-00:04:30,039 --> 00:04:31,711\r
-師傅,你看\r
-\r
-18\r
-00:04:31,759 --> 00:04:33,795\r
-前面那兒,不是有一座房子了嗎\r
-\r
-19\r
-00:04:33,839 --> 00:04:38,117\r
-我們大家進去歇息一會兒好吧\r
-\r
-20\r
-00:04:59,399 --> 00:05:02,914\r
-這個地方名叫火焰山\r
-\r
-21\r
-00:05:02,959 --> 00:05:06,031\r
-周圍有幾百里的火焰\r
-\r
-22\r
-00:05:06,079 --> 00:05:08,752\r
-一根草都不生\r
-\r
-23\r
-00:05:08,799 --> 00:05:11,632\r
-一年四季都是熱的\r
-\r
-24\r
-00:05:11,680 --> 00:05:19,633\r
-就是銅頭鐵臂要經過那個山\r
-也得融化成水\r
-\r
-25\r
-00:05:19,679 --> 00:05:23,592\r
-哪有這種事,師傅,你請放心\r
-\r
-26\r
-00:05:23,639 --> 00:05:27,154\r
-我們三個人都有法子可以過去\r
-\r
-27\r
-00:05:27,199 --> 00:05:30,714\r
-師傅,我去看看好吧\r
-\r
-28\r
-00:08:06,319 --> 00:08:09,595\r
-悟空,你去看了怎麼樣\r
-\r
-29\r
-00:08:09,639 --> 00:08:11,834\r
-厲害,厲害,真厲言\r
-\r
-30\r
-00:08:11,880 --> 00:08:15,919\r
-要不是我跑得快,尾巴都燒光了\r
-\r
-31\r
-00:08:42,720 --> 00:08:47,600\r
-老施主,這裡的火這樣大\r
-\r
-32\r
-00:08:47,600 --> 00:08:49,670\r
-這五穀從哪兒來的\r
-\r
-33\r
-00:08:49,719 --> 00:08:53,997\r
-你看這兒有一千多里的路\r
-有一位鐵扇公主\r
-\r
-34\r
-00:08:54,040 --> 00:08:56,508\r
-她有一把芭蕉扇\r
-\r
-35\r
-00:08:56,560 --> 00:08:59,074\r
-一扇呢,火就熄了\r
-\r
-36\r
-00:08:59,120 --> 00:09:01,634\r
-兩扇呢,風就來了\r
-\r
-37\r
-00:09:01,680 --> 00:09:03,989\r
-三扇呢,就下雨了\r
-\r
-38\r
-00:09:04,040 --> 00:09:07,510\r
-我們就從這個時候播種收割\r
-\r
-39\r
-00:09:07,560 --> 00:09:11,348\r
-不過,要請那位公主來\r
-\r
-40\r
-00:09:11,400 --> 00:09:14,870\r
-可不是一件容易的事\r
-\r
-41\r
-00:09:14,919 --> 00:09:16,830\r
-她住在什麼地方\r
-\r
-42\r
-00:09:16,880 --> 00:09:20,190\r
-她住在翠雲山芭蕉洞\r
-\r
-43\r
-00:09:20,240 --> 00:09:23,676\r
-是她一個人住在那兒嗎\r
-\r
-44\r
-00:09:23,720 --> 00:09:25,756\r
-她有沒有丈夫啊\r
-\r
-45\r
-00:09:25,800 --> 00:09:29,588\r
-她的丈夫是牛魔王\r
-\r
-46\r
-00:09:29,640 --> 00:09:32,200\r
-原來是老牛\r
-\r
-47\r
-00:09:32,240 --> 00:09:36,791\r
-呆子,你竟然認識他嗎?\r
-跟我一塊兒借扇子去\r
-\r
-48\r
-00:09:36,840 --> 00:09:41,755\r
-我…我知道老牛不住在那兒的\r
-\r
-49\r
-00:09:41,800 --> 00:09:46,351\r
-在他男人不在家的時候\r
-我們去找他的女人\r
-\r
-50\r
-00:09:46,400 --> 00:09:51,520\r
-這…這有點不大方便吧\r
-\r
-51\r
-00:09:51,560 --> 00:09:58,318\r
-你們…兩個人…去吧\r
-\r
-52\r
-00:09:58,360 --> 00:10:05,198\r
-我…我在…這兒…伺候師父\r
-\r
-53\r
-00:10:05,240 --> 00:10:11,270\r
-悟淨,你也跟你兩個師兄一同去吧\r
-\r
-54\r
-00:10:47,200 --> 00:10:51,557\r
-呆子,每次都是我去打頭陣的\r
-\r
-55\r
-00:10:51,600 --> 00:10:54,353\r
-這次該你去了\r
-\r
-56\r
-00:10:58,520 --> 00:11:04,914\r
-三弟,每次都是我去打頭陣\r
-這次該你去了\r
-\r
-57\r
-00:11:04,960 --> 00:11:06,837\r
-大師兄\r
-\r
-58\r
-00:11:06,880 --> 00:11:10,998\r
-我叫你去給師父出一點力\r
-你都不肯嗎\r
-\r
-59\r
-00:11:11,040 --> 00:11:14,316\r
-快去…\r
-\r
-60\r
-00:11:39,640 --> 00:11:43,040\r
-你是哪兒跑來的野和尚\r
-\r
-61\r
-00:11:43,040 --> 00:11:49,878\r
-大唐…聖僧…要你家…大公主…\r
-\r
-62\r
-00:11:49,920 --> 00:11:52,480\r
-胡說\r
-\r
-63\r
-00:12:47,559 --> 00:12:52,075\r
-大…大師兄,還是你去吧\r
-\r
-64\r
-00:12:52,120 --> 00:12:56,955\r
-呆子,你去\r
-\r
-65\r
-00:12:57,000 --> 00:13:00,709\r
-大師兄,還是你去吧\r
-\r
-66\r
-00:13:04,039 --> 00:13:07,475\r
-偷懶的東西\r
-\r
-67\r
-00:13:54,280 --> 00:13:57,909\r
-好雷公菩薩,你饒了我放了我吧\r
-\r
-68\r
-00:13:57,960 --> 00:13:59,951\r
-你跟你們公主說\r
-\r
-69\r
-00:14:00,000 --> 00:14:03,280\r
-我孫悟空要來借芭蕉扇\r
-\r
-70\r
-00:14:03,280 --> 00:14:08,400\r
-好,好,你放了我,我就去\r
-\r
-71\r
-00:14:29,560 --> 00:14:37,069\r
-奶奶,外面有一個孫悟空\r
-要來借芭蕉扇\r
-\r
-72\r
-00:14:41,520 --> 00:14:44,159\r
-快拿我的劍來\r
-\r
-73\r
-00:15:01,640 --> 00:15:04,154\r
-孫悟空,害我兒子的仇人\r
-\r
-74\r
-00:15:04,200 --> 00:15:08,557\r
-你今天也敢自己來送死嗎\r
-\r
-75\r
-00:15:08,600 --> 00:15:12,040\r
-我是從來沒見過你,怎麼會害你的兒子\r
-\r
-76\r
-00:15:12,040 --> 00:15:15,794\r
-我的孩子紅孩兒不是你害死的嗎\r
-\r
-77\r
-00:15:15,840 --> 00:15:20,391\r
-令郎已成正果,怎麼說老孫害他呢\r
-\r
-78\r
-00:15:20,440 --> 00:15:23,750\r
-少說廢話,伸過頭來讓我砍幾劍\r
-\r
-79\r
-00:15:23,800 --> 00:15:26,155\r
-受得住我就把芭蕉扇借給你\r
-\r
-80\r
-00:15:26,200 --> 00:15:28,555\r
-真的嗎\r
-\r
-81\r
-00:15:56,800 --> 00:16:00,634\r
-慢著,快把扇子借給我\r
-\r
-82\r
-00:17:53,639 --> 00:18:00,112\r
-大聖不保唐僧到西天去\r
-來到這兒做什麼\r
-\r
-83\r
-00:18:11,159 --> 00:18:17,155\r
-我被鐵扇公主一扇扇到這兒來的\r
-\r
-84\r
-00:18:17,199 --> 00:18:23,877\r
-大聖你來得巧極了\r
-我有一樣東西送給你\r
-\r
-85\r
-00:18:28,519 --> 00:18:33,468\r
-這裡是一粒定風珠,大聖你有了這珠子\r
-\r
-86\r
-00:18:33,519 --> 00:18:36,158\r
-可以使你的心堅定了\r
-\r
-87\r
-00:18:36,199 --> 00:18:39,191\r
-保那鐵扇公主扇不動你了\r
-\r
-88\r
-00:18:39,239 --> 00:18:42,868\r
-大聖你來看\r
-\r
-89\r
-00:19:00,439 --> 00:19:02,555\r
-謝謝\r
-\r
-90\r
-00:19:06,079 --> 00:19:12,314\r
-大…大師兄…不知給…\r
-\r
-91\r
-00:19:12,359 --> 00:19:18,707\r
-吹到什麼…地方去了\r
-\r
-92\r
-00:19:18,759 --> 00:19:26,109\r
-管他呢,讓猴子也吃點舌頭,我們走\r
-\r
-93\r
-00:19:35,199 --> 00:19:37,269\r
-大…大…師兄\r
-\r
-94\r
-00:19:37,319 --> 00:19:43,479\r
-你…被…被…那…\r
-\r
-95\r
-00:19:43,479 --> 00:19:50,237\r
-大師兄,你被那個婆娘扇到\r
-什麼地方去了\r
-\r
-96\r
-00:19:50,279 --> 00:19:57,196\r
-呆子,現在總該你去了\r
-\r
-97\r
-00:19:57,239 --> 00:20:00,948\r
-我不去,我要是被她一扇\r
-\r
-98\r
-00:20:00,999 --> 00:20:03,467\r
-簡直就認不得回來了\r
-\r
-99\r
-00:20:03,519 --> 00:20:09,719\r
-還是…你再去一趟吧\r
-\r
-100\r
-00:20:09,719 --> 00:20:12,233\r
-不去,不去\r
-\r
-101\r
-00:20:17,799 --> 00:20:22,793\r
-下次輪到你,可不准再偷懶了\r
-\r
-102\r
-00:20:56,159 --> 00:21:00,152\r
-這次你儘管扇,扇得我動一動\r
-\r
-103\r
-00:21:00,199 --> 00:21:05,227\r
-我不算男子漢大丈夫\r
-\r
-104\r
-00:21:33,679 --> 00:21:38,594\r
-大師兄,怎麼這回\r
-她的扇子沒有用啊\r
-\r
-105\r
-00:21:46,839 --> 00:21:50,115\r
-我們來打進去\r
-\r
-106\r
-00:23:59,639 --> 00:24:04,190\r
-快把芭蕉拿出來,給我孫悟空用一用\r
-\r
-107\r
-00:24:14,879 --> 00:24:16,915\r
-孫悟空,你在什麼地方\r
-\r
-108\r
-00:24:16,959 --> 00:24:19,996\r
-我在你肚子裡呢\r
-\r
-109\r
-00:24:45,759 --> 00:24:48,557\r
-孫悟空,你饒了我的命吧\r
-\r
-110\r
-00:24:48,599 --> 00:24:51,193\r
-你把扇子拿出來就是了\r
-\r
-111\r
-00:24:51,239 --> 00:24:56,552\r
-我答應你就是了,請你快點出來吧\r
-\r
-112\r
-00:25:00,239 --> 00:25:02,833\r
-快把扇子拿來\r
-\r
-113\r
-00:25:07,439 --> 00:25:09,236\r
-扇子已經來了\r
-\r
-114\r
-00:25:09,280 --> 00:25:12,078\r
-孫悟空你怎麼還不出來呢\r
-\r
-115\r
-00:25:12,119 --> 00:25:16,635\r
-你把嘴張開來,我就出來了\r
-\r
-116\r
-00:25:25,359 --> 00:25:29,432\r
-孫祖宗,你怎麼還不出來呢\r
-\r
-117\r
-00:25:50,359 --> 00:25:55,592\r
-我在這兒呢,借給我用用就還你的\r
-\r
-118\r
-00:26:32,559 --> 00:26:36,598\r
-師父等了好久了,我們快去吧\r
-\r
-119\r
-00:27:01,879 --> 00:27:04,916\r
-經,經是什麼\r
-\r
-120\r
-00:27:04,959 --> 00:27:10,039\r
-經是天地之間不能辨易的道理\r
-\r
-121\r
-00:27:10,039 --> 00:27:14,191\r
-這個道理也就是做人的道理\r
-\r
-122\r
-00:27:14,239 --> 00:27:18,710\r
-任何一個人有了這個道理\r
-\r
-123\r
-00:27:18,759 --> 00:27:25,358\r
-才可以免去諸般痛苦\r
-好好的安居樂業\r
-\r
-124\r
-00:27:25,399 --> 00:27:29,950\r
-實實在在的過日子\r
-\r
-125\r
-00:27:34,680 --> 00:27:36,352\r
-反過來說\r
-\r
-126\r
-00:27:36,399 --> 00:27:40,108\r
-要是做人不曉得這個道理\r
-\r
-127\r
-00:27:40,159 --> 00:27:46,394\r
-就跟沉陷在苦海裡頭一樣\r
-一生一世\r
-\r
-128\r
-00:27:46,439 --> 00:27:52,628\r
-甚至於子孫孫,都得不到幸福\r
-\r
-129\r
-00:27:52,679 --> 00:27:55,671\r
-我為什麼要去取經\r
-\r
-130\r
-00:27:55,719 --> 00:28:01,316\r
-就是因為現在的人都陷在苦海裡了\r
-\r
-131\r
-00:28:01,359 --> 00:28:04,192\r
-要想成就這此些人\r
-\r
-132\r
-00:28:04,239 --> 00:28:12,510\r
-所以在大唐皇帝面前討下這\r
-重大繁難的差事\r
-\r
-133\r
-00:28:15,679 --> 00:28:17,829\r
-芭蕉扇借到了沒有\r
-\r
-134\r
-00:28:17,879 --> 00:28:19,517\r
-借來了\r
-\r
-135\r
-00:28:19,559 --> 00:28:22,790\r
-是不是這個\r
-\r
-136\r
-00:28:22,839 --> 00:28:27,993\r
-諸位施主,現在扇子既然借到了\r
-\r
-137\r
-00:28:28,039 --> 00:28:32,157\r
-貧僧師徒就要告辭了\r
-\r
-138\r
-00:28:32,199 --> 00:28:34,040\r
-慢一點\r
-\r
-139\r
-00:28:34,040 --> 00:28:39,797\r
-諸位,我想留聖僧在這兒多住幾天\r
-\r
-140\r
-00:28:39,839 --> 00:28:41,352\r
-好不好啊\r
-\r
-141\r
-00:28:41,399 --> 00:28:43,469\r
-好的,好的\r
-\r
-142\r
-00:28:43,519 --> 00:28:45,908\r
-謝謝諸位的好意\r
-\r
-143\r
-00:28:45,959 --> 00:28:51,795\r
-我早走一步就是早一步完成\r
-我們的任務\r
-\r
-144\r
-00:28:51,839 --> 00:28:56,196\r
-那麼就請令高徒先到火焰山\r
-\r
-145\r
-00:28:56,239 --> 00:29:02,155\r
-扇滅了火之後,再陪聖僧同行\r
-\r
-146\r
-00:29:02,199 --> 00:29:05,475\r
-好,你就去吧\r
-\r
-147\r
-00:30:24,479 --> 00:30:30,039\r
-鐵扇公主真可惡,拿假的芭蕉扇\r
-來騙我\r
-\r
-148\r
-00:30:30,039 --> 00:30:32,792\r
-我非殺了她不可\r
-\r
-149\r
-00:30:32,839 --> 00:30:36,309\r
-不,殺了她也是枉然\r
-\r
-150\r
-00:30:36,359 --> 00:30:39,590\r
-我素來不願意你多殺人\r
-\r
-151\r
-00:30:39,639 --> 00:30:42,995\r
-我們再想辦法\r
-\r
-152\r
-00:30:52,159 --> 00:30:56,232\r
-師兄,怎麼你也會上她的當\r
-\r
-153\r
-00:30:56,279 --> 00:30:58,554\r
-費了這麼許多的力氣\r
-\r
-154\r
-00:30:58,599 --> 00:31:02,114\r
-卻弄了一把假的扇子來\r
-\r
-155\r
-00:31:02,159 --> 00:31:06,516\r
-笑話,笑話\r
-\r
-156\r
-00:31:08,919 --> 00:31:10,432\r
-那麼你去\r
-\r
-157\r
-00:31:10,479 --> 00:31:14,392\r
-好好,我去我去,我就去\r
-\r
-158\r
-00:31:14,439 --> 00:31:17,033\r
-我去找牛魔王\r
-\r
-159\r
-00:31:17,119 --> 00:31:19,952\r
-這倒是一個好辦法\r
-\r
-160\r
-00:31:21,399 --> 00:31:24,550\r
-師兄,你看好不好\r
-\r
-161\r
-00:31:24,599 --> 00:31:27,397\r
-好,看你的了\r
-\r
-162\r
-00:33:07,199 --> 00:33:11,159\r
-你看我今天化妝得好嗎\r
-\r
-163\r
-00:33:11,159 --> 00:33:13,798\r
-好極了,我的小寶貝\r
-\r
-164\r
-00:33:13,839 --> 00:33:17,070\r
-你陪我到洞外頭去走走,好不好\r
-\r
-165\r
-00:33:17,119 --> 00:33:21,556\r
-我的寶貝,還是你一個人去吧\r
-\r
-166\r
-00:33:21,599 --> 00:33:24,830\r
-本來嘛,我們這種草婆子\r
-\r
-167\r
-00:33:24,879 --> 00:33:28,030\r
-跟你出去了會使你丟臉的\r
-\r
-168\r
-00:33:28,079 --> 00:33:32,039\r
-小寶貝,這是什麼話呢\r
-\r
-169\r
-00:33:32,039 --> 00:33:37,511\r
-你先去,我隨後就來好不好\r
-\r
-170\r
-00:35:28,039 --> 00:35:35,673\r
-女菩薩,你真是天仙下凡\r
-\r
-171\r
-00:35:35,719 --> 00:35:37,914\r
-你…你是什麼人\r
-\r
-172\r
-00:35:37,959 --> 00:35:41,474\r
-我是從芭蕉洞來找牛魔王的\r
-\r
-173\r
-00:35:41,520 --> 00:35:43,988\r
-快放手\r
-\r
-174\r
-00:35:49,559 --> 00:35:52,949\r
-女菩薩,你慢點走\r
-\r
-175\r
-00:36:44,239 --> 00:36:49,233\r
-小寶貝,誰來欺負你\r
-\r
-176\r
-00:36:49,279 --> 00:36:50,837\r
-是你\r
-\r
-177\r
-00:36:50,879 --> 00:36:54,349\r
-我哪裡捨得欺負你呢\r
-\r
-178\r
-00:36:56,919 --> 00:36:59,274\r
-你還是回芭蕉洞去吧\r
-\r
-179\r
-00:36:59,320 --> 00:37:01,709\r
-省得那個不要臉的東西\r
-\r
-180\r
-00:37:01,759 --> 00:37:07,675\r
-時常派人來請你,欺負我\r
-\r
-181\r
-00:37:07,719 --> 00:37:11,075\r
-你說有人來找我\r
-\r
-182\r
-00:37:11,119 --> 00:37:15,078\r
-外邊有一個豬臉的和尚來請你\r
-\r
-183\r
-00:37:15,120 --> 00:37:18,510\r
-差一點把我嚇死了\r
-\r
-184\r
-00:37:18,559 --> 00:37:22,757\r
-真有這回事嗎?待我出去看一看\r
-\r
-185\r
-00:37:50,679 --> 00:37:53,796\r
-牛大哥\r
-\r
-186\r
-00:37:53,839 --> 00:37:58,151\r
-這裡頭有個頂漂亮的小娘們\r
-\r
-187\r
-00:37:58,200 --> 00:38:03,991\r
-呸,那是我的女人,你為什麼要欺負她\r
-\r
-188\r
-00:38:04,039 --> 00:38:08,559\r
-大哥,我不知那就是二嫂,請原瓊\r
-\r
-189\r
-00:38:08,559 --> 00:38:11,949\r
-不知道不見罪,好啊,你走啊\r
-\r
-190\r
-00:38:11,999 --> 00:38:16,117\r
-不不不,我還有事情請大哥幫忙\r
-\r
-191\r
-00:38:18,479 --> 00:38:24,719\r
-小弟保唐僧取經,路過火焰山\r
-\r
-192\r
-00:38:24,719 --> 00:38:27,313\r
-請大哥跟嫂子說一聲\r
-\r
-193\r
-00:38:27,359 --> 00:38:30,829\r
-把這個芭蕉扇借來用一用\r
-\r
-194\r
-00:38:30,880 --> 00:38:33,519\r
-不成,那唐僧和孫悟空\r
-\r
-195\r
-00:38:33,519 --> 00:38:35,191\r
-是我孩子的仇人\r
-\r
-196\r
-00:38:35,239 --> 00:38:38,754\r
-我正要抓他們報仇\r
-\r
-197\r
-00:38:38,799 --> 00:38:44,988\r
-令郎已成正果,請大哥不必再計較吧\r
-\r
-198\r
-00:38:45,039 --> 00:38:48,952\r
-好,看在我們從前的交情\r
-我不跟你計較\r
-\r
-199\r
-00:38:49,000 --> 00:38:51,719\r
-那麼去吧\r
-\r
-200\r
-00:39:38,399 --> 00:39:44,190\r
-寶貝,那個豬臉和尚\r
-是我從前一個朋友\r
-\r
-201\r
-00:39:44,239 --> 00:39:46,514\r
-並不是芭蕉洞派來的\r
-\r
-202\r
-00:39:46,559 --> 00:39:47,753\r
-我不相信\r
-\r
-203\r
-00:39:47,799 --> 00:39:50,950\r
-我不騙你\r
-\r
-204\r
-00:39:50,999 --> 00:39:54,036\r
-現在那個和尚到哪兒去了呢\r
-\r
-205\r
-00:39:54,119 --> 00:39:57,794\r
-已經被我打走了\r
-\r
-206\r
-00:43:58,639 --> 00:44:01,358\r
-大王回來了\r
-\r
-207\r
-00:44:01,399 --> 00:44:02,388\r
-奶奶呢\r
-\r
-208\r
-00:44:02,439 --> 00:44:04,794\r
-在裡邊\r
-\r
-209\r
-00:44:42,999 --> 00:44:48,232\r
-今天是什麼風會把大王吹到這兒來的\r
-\r
-210\r
-00:44:48,279 --> 00:44:52,272\r
-聽到孫悟空保唐僧快到這兒\r
-\r
-211\r
-00:44:52,320 --> 00:44:56,916\r
-恐怕他要來借芭蕉扇過火焰山\r
-\r
-212\r
-00:44:56,959 --> 00:45:00,872\r
-那猴子是害我們兒子的仇人\r
-\r
-213\r
-00:45:00,919 --> 00:45:08,507\r
-早晚來了抓著他,讓我們夫妻出出恨\r
-\r
-214\r
-00:45:08,559 --> 00:45:12,711\r
-夫人,你為什麼哭\r
-\r
-215\r
-00:45:12,759 --> 00:45:15,717\r
-那猴子已經來過了\r
-\r
-216\r
-00:45:15,759 --> 00:45:18,876\r
-是我不肯把扇子借給他\r
-\r
-217\r
-00:45:18,919 --> 00:45:22,275\r
-不知道怎麼會跑到我的肚子裡來\r
-\r
-218\r
-00:45:22,319 --> 00:45:25,516\r
-弄得我肚子痛得要命\r
-\r
-219\r
-00:45:25,559 --> 00:45:31,399\r
-後來我沒有法子,只好把扇子借給他\r
-\r
-220\r
-00:45:31,399 --> 00:45:38,271\r
-可惜可惜,你怎麼把扇子借給他\r
-\r
-221\r
-00:45:38,320 --> 00:45:40,470\r
-拿去的是假的\r
-\r
-222\r
-00:45:40,519 --> 00:45:43,033\r
-假的\r
-\r
-223\r
-00:46:14,199 --> 00:46:19,876\r
-開筵慶祝大王歸\r
-\r
-224\r
-00:46:19,919 --> 00:46:25,630\r
-好酒殷勤勸幾杯\r
-\r
-225\r
-00:46:25,679 --> 00:46:34,189\r
-雞又香,鴨又美,豬又肥\r
-\r
-226\r
-00:46:34,240 --> 00:46:45,674\r
-我盡量的歌,我盡量的舞\r
-\r
-227\r
-00:46:45,719 --> 00:46:54,514\r
-你也要盡量的醉\r
-\r
-228\r
-00:47:03,599 --> 00:47:16,399\r
-大王啊,你把舊人丟\r
-\r
-229\r
-00:47:16,439 --> 00:47:22,628\r
-你愛新人媚\r
-\r
-230\r
-00:47:22,679 --> 00:47:36,673\r
-為你淌了多少相思淚\r
-\r
-231\r
-00:47:46,719 --> 00:47:55,718\r
-等一會燈兒吹帳兒垂\r
-\r
-232\r
-00:47:55,759 --> 00:48:00,879\r
-你獨自兒睡\r
-\r
-233\r
-00:48:00,879 --> 00:48:05,519\r
-也嘗嘗這個淒涼味\r
-\r
-234\r
-00:48:05,519 --> 00:48:13,437\r
-恕我不奉陪\r
-\r
-235\r
-00:48:18,559 --> 00:48:24,634\r
-就是同床\r
-\r
-236\r
-00:48:24,679 --> 00:48:34,350\r
-我們各人蓋著各人的被\r
-\r
-237\r
-00:48:38,399 --> 00:48:42,392\r
-大王,我醉了\r
-\r
-238\r
-00:48:55,079 --> 00:48:58,151\r
-夫人,那真扇子你放在什麼地方\r
-\r
-239\r
-00:48:58,199 --> 00:49:05,469\r
-那猴子花樣很多,而且那豬八戒\r
-本事更大\r
-\r
-240\r
-00:49:05,519 --> 00:49:09,797\r
-當心給他們騙了去\r
-\r
-241\r
-00:49:18,360 --> 00:49:21,989\r
-寶貝不是在這兒嗎\r
-\r
-242\r
-00:49:31,439 --> 00:49:39,319\r
-大王,你出神想什麼呢?\r
-還是收了吧\r
-\r
-243\r
-00:49:39,319 --> 00:49:43,551\r
-小寶貝\r
-\r
-244\r
-00:49:43,599 --> 00:49:49,037\r
-寶貝,你多喝一杯,你喝啊\r
-\r
-245\r
-00:49:53,919 --> 00:49:59,519\r
-今兒晚上,金龍大王\r
-還要請我去喝酒呢\r
-\r
-246\r
-00:49:59,519 --> 00:50:01,430\r
-那你就該去了\r
-\r
-247\r
-00:50:01,479 --> 00:50:02,878\r
-是的\r
-\r
-248\r
-00:50:02,919 --> 00:50:06,628\r
-你去替爺爺把金睛獸牽出去預備好\r
-\r
-249\r
-00:50:06,679 --> 00:50:08,271\r
-是\r
-\r
-250\r
-00:50:08,320 --> 00:50:12,598\r
-可是,你今兒個晚上去要少喝一點兒\r
-\r
-251\r
-00:50:12,639 --> 00:50:15,756\r
-免得回來睡著叫不醒你\r
-\r
-252\r
-00:50:15,800 --> 00:50:19,110\r
-不好了,爺爺那個金隋獸不見了\r
-\r
-253\r
-00:50:19,159 --> 00:50:20,911\r
-你們全都是死人嗎\r
-\r
-254\r
-00:50:20,959 --> 00:50:24,039\r
-家裡頭的東西怎麼會不見了呢\r
-\r
-255\r
-00:50:24,039 --> 00:50:27,918\r
-寶貝,不要管他們吧\r
-\r
-256\r
-00:50:27,960 --> 00:50:31,714\r
-恐怕是那豬八戒偷了去了\r
-\r
-257\r
-00:50:31,759 --> 00:50:35,274\r
-說不定我要到芭蕉洞去一趟\r
-\r
-258\r
-00:50:35,320 --> 00:50:39,313\r
-原來是你們做好了的圈套\r
-\r
-259\r
-00:50:42,280 --> 00:50:48,150\r
-你還是要到那個不要臉的女人那兒去\r
-\r
-260\r
-00:50:48,199 --> 00:50:50,713\r
-好寶貝,你不要哭了\r
-\r
-261\r
-00:50:50,759 --> 00:50:54,069\r
-我去去就來的\r
-\r
-262\r
-00:51:02,679 --> 00:51:07,309\r
-來來,喝喝\r
-\r
-263\r
-00:51:10,359 --> 00:51:12,475\r
-我現在放心了\r
-\r
-264\r
-00:51:12,519 --> 00:51:16,717\r
-不怕他們偷我們的寶貝\r
-\r
-265\r
-00:51:16,759 --> 00:51:21,310\r
-他們就是偷了去\r
-不知道把那絲線一拉\r
-\r
-266\r
-00:51:21,360 --> 00:51:26,275\r
-單是一顆珠子也沒有用處啊\r
-\r
-267\r
-00:51:26,319 --> 00:51:31,791\r
-是不是那麼一拉就變成扇子\r
-\r
-268\r
-00:51:35,120 --> 00:51:38,078\r
-大王,你今天喝醉了\r
-\r
-269\r
-00:51:38,119 --> 00:51:44,035\r
-自己的寶貝都忘了,還來問我\r
-\r
-270\r
-00:51:49,999 --> 00:51:53,708\r
-娘子,你看看我是誰\r
-\r
-271\r
-00:52:00,320 --> 00:52:03,756\r
-你是什麼人\r
-\r
-272\r
-00:52:03,799 --> 00:52:09,908\r
-我是唐僧的二徒弟,豬八戒\r
-\r
-273\r
-00:52:09,959 --> 00:52:14,794\r
-對不住,謝謝你,打擾了\r
-\r
-274\r
-00:52:19,080 --> 00:52:21,719\r
-再見\r
-\r
-275\r
-00:53:06,839 --> 00:53:10,718\r
-牛大嫂太風騷\r
-\r
-276\r
-00:53:10,760 --> 00:53:14,719\r
-眾小妖都俊俏\r
-\r
-277\r
-00:53:14,759 --> 00:53:24,828\r
-老豬真有點受不了\r
-\r
-278\r
-00:53:24,879 --> 00:53:28,872\r
-心機巧,手段妙\r
-\r
-279\r
-00:53:28,919 --> 00:53:32,832\r
-居然騙得了無價寶\r
-\r
-280\r
-00:53:32,880 --> 00:53:36,793\r
-這一番勞苦功高\r
-\r
-281\r
-00:53:36,839 --> 00:53:38,318\r
-沙僧該拜倒\r
-\r
-282\r
-00:53:38,359 --> 00:53:40,748\r
-猴兒該領教\r
-\r
-283\r
-00:53:40,799 --> 00:53:45,236\r
-師父也要嚇一跳\r
-\r
-284\r
-00:53:45,280 --> 00:53:49,193\r
-我老豬也有今朝\r
-\r
-285\r
-00:53:49,239 --> 00:53:54,359\r
-我老豬也有今朝\r
-\r
-286\r
-00:54:36,720 --> 00:54:40,474\r
-呆子,事情辦得怎麼樣了\r
-\r
-287\r
-00:54:40,519 --> 00:54:42,828\r
-不僅扇子到手\r
-\r
-288\r
-00:54:42,880 --> 00:54:48,796\r
-鐵扇公主並且還做了我\r
-半天的老婆\r
-\r
-289\r
-00:54:48,839 --> 00:54:51,717\r
-這倒便宜了你了\r
-\r
-290\r
-00:54:58,159 --> 00:55:01,595\r
-扇子拿來給我看看\r
-\r
-291\r
-00:55:16,039 --> 00:55:20,237\r
-你怎麼會把它縮小了的呀\r
-\r
-292\r
-00:55:40,559 --> 00:55:45,349\r
-老豬,你可認識我嗎\r
-\r
-293\r
-00:55:45,399 --> 00:55:49,187\r
-你不要跟我開玩笑了\r
-\r
-294\r
-00:55:49,239 --> 00:55:52,151\r
-誰跟你開玩笑\r
-\r
-295\r
-00:56:42,879 --> 00:56:45,393\r
-呆子,你去了怎麼樣\r
-\r
-296\r
-00:56:45,439 --> 00:56:47,111\r
-白跑了一趟\r
-\r
-297\r
-00:56:47,159 --> 00:56:49,992\r
-悟能,扇子借來沒有\r
-\r
-298\r
-00:56:50,039 --> 00:56:53,349\r
-我去找牛魔王,他不肯借\r
-\r
-299\r
-00:56:53,400 --> 00:56:59,191\r
-後來,我又變成老牛的樣子\r
-\r
-300\r
-00:56:59,239 --> 00:57:03,551\r
-在鐵扇公主那兒把扇子已經騙過來了\r
-\r
-301\r
-00:57:03,599 --> 00:57:10,599\r
-誰知道他又變成你的樣子又給他騙回去了\r
-\r
-302\r
-00:57:10,599 --> 00:57:12,749\r
-老牛的本領大\r
-\r
-303\r
-00:57:12,800 --> 00:57:16,156\r
-我還被他揍了一頓呢\r
-\r
-304\r
-00:57:16,199 --> 00:57:21,398\r
-呆子,你能辦這樣大的事那\r
-還算是呆子嗎\r
-\r
-305\r
-00:57:21,439 --> 00:57:25,671\r
-事情不都環在你頭上\r
-\r
-306\r
-00:57:30,759 --> 00:57:34,388\r
-你們不要吵了,趕緊再想辦法\r
-\r
-307\r
-00:57:34,439 --> 00:57:40,275\r
-哪一方…沒…沒有火啊\r
-\r
-308\r
-00:57:40,320 --> 00:57:47,078\r
-東南西北,只有西方有火\r
-\r
-309\r
-00:57:47,120 --> 00:57:50,749\r
-那我們不是要走回去了嗎\r
-\r
-310\r
-00:57:50,799 --> 00:57:52,949\r
-這路不通,不回去怎麼樣呢\r
-\r
-311\r
-00:57:52,999 --> 00:57:55,229\r
-八戒,你不要這樣說\r
-\r
-312\r
-00:57:55,279 --> 00:57:59,158\r
-要成功一件事情總是有阻礙的\r
-\r
-313\r
-00:57:59,199 --> 00:58:04,557\r
-我們要做這樣神聖的事情\r
-就要堅定我們的信念\r
-\r
-314\r
-00:58:04,599 --> 00:58:09,229\r
-不能因為有一點兒困難\r
-就中適改變我們的宗旨\r
-\r
-315\r
-00:58:09,280 --> 00:58:14,593\r
-你們這次失敗的原因是由於\r
-既不同心又不合力\r
-\r
-316\r
-00:58:14,639 --> 00:58:17,153\r
-假使你們三個人一條心\r
-\r
-317\r
-00:58:17,199 --> 00:58:20,509\r
-合起力量,共同跟牛魔王決鬥\r
-\r
-318\r
-00:58:20,559 --> 00:58:22,868\r
-事情一定可以成功的\r
-\r
-319\r
-00:58:22,919 --> 00:58:26,039\r
-我們謹遵師父的命令\r
-\r
-320\r
-00:58:26,039 --> 00:58:30,157\r
-去跟牛魔王爭一個誰勝誰敗\r
-\r
-321\r
-00:58:30,199 --> 00:58:34,272\r
-誰…誰…誰勝誰敗\r
-\r
-322\r
-00:58:34,320 --> 00:58:37,710\r
-那就好極了\r
-\r
-323\r
-00:58:37,759 --> 00:58:40,990\r
-各位受他的害處也不小了\r
-\r
-324\r
-00:58:41,040 --> 00:58:43,879\r
-希望各位也出此些力量\r
-\r
-325\r
-00:58:43,879 --> 00:58:49,590\r
-跟小徒們共同征服牛魔王,消滅火焰山\r
-\r
-326\r
-00:58:49,639 --> 00:58:53,837\r
-免除永遠的禍害\r
-\r
-327\r
-00:58:53,879 --> 00:58:57,508\r
-我們聽從師父的命令,為大家謀幸福\r
-\r
-328\r
-00:58:57,559 --> 00:58:58,878\r
-大家一起出力去\r
-\r
-329\r
-00:58:58,919 --> 00:59:01,035\r
-好\r
-\r
-330\r
-01:08:23,239 --> 01:08:25,628\r
-奶奶,不好了\r
-\r
-331\r
-01:08:25,679 --> 01:08:30,799\r
-爺爺給人家抓住了,你快點去看看吧\r
-\r
-332\r
-01:08:54,479 --> 01:08:56,709\r
-還不過來打,過來打\r
-\r
-333\r
-01:08:56,760 --> 01:08:59,718\r
-慢一點,慢一點\r
-\r
-334\r
-01:08:59,760 --> 01:09:05,790\r
-孽畜,只要你把扇子交出來,饒你不死\r
-\r
-335\r
-01:09:05,840 --> 01:09:12,757\r
-老牛,扇子在什麼地方?快拿出來啊\r
-\r
-336\r
-01:09:12,799 --> 01:09:19,352\r
-在我老…老婆那兒\r
-\r
-337\r
-01:09:25,240 --> 01:09:27,993\r
-夫人,夫人,夫人\r
-\r
-338\r
-01:09:28,039 --> 01:09:32,271\r
-你快點來救救我\r
-\r
-339\r
-01:09:32,320 --> 01:09:35,118\r
-把扇子拿出來吧\r
-\r
-340\r
-01:09:35,159 --> 01:09:39,630\r
-大王,好,好的\r
-\r
-341\r
-01:09:43,400 --> 01:09:47,234\r
-悟空,你再去一趟吧\r
-\r
+1
+00:00:01,080 --> 00:00:09,078
+片名:鐵扇公主
+
+2
+00:02:03,119 --> 00:02:09,280
+西遊記,本為一部絕妙之童話
+
+3
+00:02:09,280 --> 00:02:15,280
+特以世多誤解,致被目為神怪小說
+
+4
+00:02:15,280 --> 00:02:19,240
+本片取材於是
+
+5
+00:02:19,240 --> 00:02:24,240
+實為培育兒童心理而作
+
+6
+00:02:24,240 --> 00:02:29,280
+故內容刪蕪存精,不涉神怪
+
+7
+00:02:29,280 --> 00:02:32,560
+僅以唐僧等四人路阻火焰山
+
+8
+00:02:32,560 --> 00:02:41,040
+以示人生途徑中之磨難
+
+9
+00:02:41,040 --> 00:02:46,440
+欲求經此磨難,則必須堅持信念
+大眾一心
+
+10
+00:02:46,440 --> 00:02:52,436
+始能獲得此撲滅凶焰之芭蕉扇
+
+11
+00:03:34,480 --> 00:03:37,790
+現在已經秋天了,怎麼還這麼熱
+
+12
+00:03:37,840 --> 00:03:42,356
+呆子,不要說廢話,趕路要緊
+
+13
+00:04:06,920 --> 00:04:09,354
+悟空,這是到了什麼地方
+
+14
+00:04:09,400 --> 00:04:13,678
+反正是我們上西天必定要經過的地方
+
+15
+00:04:13,720 --> 00:04:18,111
+我們沒有走錯路線吧
+
+16
+00:04:18,159 --> 00:04:22,311
+為什麼這個地方這麼樣的熱呢
+
+17
+00:04:30,039 --> 00:04:31,711
+師傅,你看
+
+18
+00:04:31,759 --> 00:04:33,795
+前面那兒,不是有一座房子了嗎
+
+19
+00:04:33,839 --> 00:04:38,117
+我們大家進去歇息一會兒好吧
+
+20
+00:04:59,399 --> 00:05:02,914
+這個地方名叫火焰山
+
+21
+00:05:02,959 --> 00:05:06,031
+周圍有幾百里的火焰
+
+22
+00:05:06,079 --> 00:05:08,752
+一根草都不生
+
+23
+00:05:08,799 --> 00:05:11,632
+一年四季都是熱的
+
+24
+00:05:11,680 --> 00:05:19,633
+就是銅頭鐵臂要經過那個山
+也得融化成水
+
+25
+00:05:19,679 --> 00:05:23,592
+哪有這種事,師傅,你請放心
+
+26
+00:05:23,639 --> 00:05:27,154
+我們三個人都有法子可以過去
+
+27
+00:05:27,199 --> 00:05:30,714
+師傅,我去看看好吧
+
+28
+00:08:06,319 --> 00:08:09,595
+悟空,你去看了怎麼樣
+
+29
+00:08:09,639 --> 00:08:11,834
+厲害,厲害,真厲言
+
+30
+00:08:11,880 --> 00:08:15,919
+要不是我跑得快,尾巴都燒光了
+
+31
+00:08:42,720 --> 00:08:47,600
+老施主,這裡的火這樣大
+
+32
+00:08:47,600 --> 00:08:49,670
+這五穀從哪兒來的
+
+33
+00:08:49,719 --> 00:08:53,997
+你看這兒有一千多里的路
+有一位鐵扇公主
+
+34
+00:08:54,040 --> 00:08:56,508
+她有一把芭蕉扇
+
+35
+00:08:56,560 --> 00:08:59,074
+一扇呢,火就熄了
+
+36
+00:08:59,120 --> 00:09:01,634
+兩扇呢,風就來了
+
+37
+00:09:01,680 --> 00:09:03,989
+三扇呢,就下雨了
+
+38
+00:09:04,040 --> 00:09:07,510
+我們就從這個時候播種收割
+
+39
+00:09:07,560 --> 00:09:11,348
+不過,要請那位公主來
+
+40
+00:09:11,400 --> 00:09:14,870
+可不是一件容易的事
+
+41
+00:09:14,919 --> 00:09:16,830
+她住在什麼地方
+
+42
+00:09:16,880 --> 00:09:20,190
+她住在翠雲山芭蕉洞
+
+43
+00:09:20,240 --> 00:09:23,676
+是她一個人住在那兒嗎
+
+44
+00:09:23,720 --> 00:09:25,756
+她有沒有丈夫啊
+
+45
+00:09:25,800 --> 00:09:29,588
+她的丈夫是牛魔王
+
+46
+00:09:29,640 --> 00:09:32,200
+原來是老牛
+
+47
+00:09:32,240 --> 00:09:36,791
+呆子,你竟然認識他嗎?
+跟我一塊兒借扇子去
+
+48
+00:09:36,840 --> 00:09:41,755
+我…我知道老牛不住在那兒的
+
+49
+00:09:41,800 --> 00:09:46,351
+在他男人不在家的時候
+我們去找他的女人
+
+50
+00:09:46,400 --> 00:09:51,520
+這…這有點不大方便吧
+
+51
+00:09:51,560 --> 00:09:58,318
+你們…兩個人…去吧
+
+52
+00:09:58,360 --> 00:10:05,198
+我…我在…這兒…伺候師父
+
+53
+00:10:05,240 --> 00:10:11,270
+悟淨,你也跟你兩個師兄一同去吧
+
+54
+00:10:47,200 --> 00:10:51,557
+呆子,每次都是我去打頭陣的
+
+55
+00:10:51,600 --> 00:10:54,353
+這次該你去了
+
+56
+00:10:58,520 --> 00:11:04,914
+三弟,每次都是我去打頭陣
+這次該你去了
+
+57
+00:11:04,960 --> 00:11:06,837
+大師兄
+
+58
+00:11:06,880 --> 00:11:10,998
+我叫你去給師父出一點力
+你都不肯嗎
+
+59
+00:11:11,040 --> 00:11:14,316
+快去…
+
+60
+00:11:39,640 --> 00:11:43,040
+你是哪兒跑來的野和尚
+
+61
+00:11:43,040 --> 00:11:49,878
+大唐…聖僧…要你家…大公主…
+
+62
+00:11:49,920 --> 00:11:52,480
+胡說
+
+63
+00:12:47,559 --> 00:12:52,075
+大…大師兄,還是你去吧
+
+64
+00:12:52,120 --> 00:12:56,955
+呆子,你去
+
+65
+00:12:57,000 --> 00:13:00,709
+大師兄,還是你去吧
+
+66
+00:13:04,039 --> 00:13:07,475
+偷懶的東西
+
+67
+00:13:54,280 --> 00:13:57,909
+好雷公菩薩,你饒了我放了我吧
+
+68
+00:13:57,960 --> 00:13:59,951
+你跟你們公主說
+
+69
+00:14:00,000 --> 00:14:03,280
+我孫悟空要來借芭蕉扇
+
+70
+00:14:03,280 --> 00:14:08,400
+好,好,你放了我,我就去
+
+71
+00:14:29,560 --> 00:14:37,069
+奶奶,外面有一個孫悟空
+要來借芭蕉扇
+
+72
+00:14:41,520 --> 00:14:44,159
+快拿我的劍來
+
+73
+00:15:01,640 --> 00:15:04,154
+孫悟空,害我兒子的仇人
+
+74
+00:15:04,200 --> 00:15:08,557
+你今天也敢自己來送死嗎
+
+75
+00:15:08,600 --> 00:15:12,040
+我是從來沒見過你,怎麼會害你的兒子
+
+76
+00:15:12,040 --> 00:15:15,794
+我的孩子紅孩兒不是你害死的嗎
+
+77
+00:15:15,840 --> 00:15:20,391
+令郎已成正果,怎麼說老孫害他呢
+
+78
+00:15:20,440 --> 00:15:23,750
+少說廢話,伸過頭來讓我砍幾劍
+
+79
+00:15:23,800 --> 00:15:26,155
+受得住我就把芭蕉扇借給你
+
+80
+00:15:26,200 --> 00:15:28,555
+真的嗎
+
+81
+00:15:56,800 --> 00:16:00,634
+慢著,快把扇子借給我
+
+82
+00:17:53,639 --> 00:18:00,112
+大聖不保唐僧到西天去
+來到這兒做什麼
+
+83
+00:18:11,159 --> 00:18:17,155
+我被鐵扇公主一扇扇到這兒來的
+
+84
+00:18:17,199 --> 00:18:23,877
+大聖你來得巧極了
+我有一樣東西送給你
+
+85
+00:18:28,519 --> 00:18:33,468
+這裡是一粒定風珠,大聖你有了這珠子
+
+86
+00:18:33,519 --> 00:18:36,158
+可以使你的心堅定了
+
+87
+00:18:36,199 --> 00:18:39,191
+保那鐵扇公主扇不動你了
+
+88
+00:18:39,239 --> 00:18:42,868
+大聖你來看
+
+89
+00:19:00,439 --> 00:19:02,555
+謝謝
+
+90
+00:19:06,079 --> 00:19:12,314
+大…大師兄…不知給…
+
+91
+00:19:12,359 --> 00:19:18,707
+吹到什麼…地方去了
+
+92
+00:19:18,759 --> 00:19:26,109
+管他呢,讓猴子也吃點舌頭,我們走
+
+93
+00:19:35,199 --> 00:19:37,269
+大…大…師兄
+
+94
+00:19:37,319 --> 00:19:43,479
+你…被…被…那…
+
+95
+00:19:43,479 --> 00:19:50,237
+大師兄,你被那個婆娘扇到
+什麼地方去了
+
+96
+00:19:50,279 --> 00:19:57,196
+呆子,現在總該你去了
+
+97
+00:19:57,239 --> 00:20:00,948
+我不去,我要是被她一扇
+
+98
+00:20:00,999 --> 00:20:03,467
+簡直就認不得回來了
+
+99
+00:20:03,519 --> 00:20:09,719
+還是…你再去一趟吧
+
+100
+00:20:09,719 --> 00:20:12,233
+不去,不去
+
+101
+00:20:17,799 --> 00:20:22,793
+下次輪到你,可不准再偷懶了
+
+102
+00:20:56,159 --> 00:21:00,152
+這次你儘管扇,扇得我動一動
+
+103
+00:21:00,199 --> 00:21:05,227
+我不算男子漢大丈夫
+
+104
+00:21:33,679 --> 00:21:38,594
+大師兄,怎麼這回
+她的扇子沒有用啊
+
+105
+00:21:46,839 --> 00:21:50,115
+我們來打進去
+
+106
+00:23:59,639 --> 00:24:04,190
+快把芭蕉拿出來,給我孫悟空用一用
+
+107
+00:24:14,879 --> 00:24:16,915
+孫悟空,你在什麼地方
+
+108
+00:24:16,959 --> 00:24:19,996
+我在你肚子裡呢
+
+109
+00:24:45,759 --> 00:24:48,557
+孫悟空,你饒了我的命吧
+
+110
+00:24:48,599 --> 00:24:51,193
+你把扇子拿出來就是了
+
+111
+00:24:51,239 --> 00:24:56,552
+我答應你就是了,請你快點出來吧
+
+112
+00:25:00,239 --> 00:25:02,833
+快把扇子拿來
+
+113
+00:25:07,439 --> 00:25:09,236
+扇子已經來了
+
+114
+00:25:09,280 --> 00:25:12,078
+孫悟空你怎麼還不出來呢
+
+115
+00:25:12,119 --> 00:25:16,635
+你把嘴張開來,我就出來了
+
+116
+00:25:25,359 --> 00:25:29,432
+孫祖宗,你怎麼還不出來呢
+
+117
+00:25:50,359 --> 00:25:55,592
+我在這兒呢,借給我用用就還你的
+
+118
+00:26:32,559 --> 00:26:36,598
+師父等了好久了,我們快去吧
+
+119
+00:27:01,879 --> 00:27:04,916
+經,經是什麼
+
+120
+00:27:04,959 --> 00:27:10,039
+經是天地之間不能辨易的道理
+
+121
+00:27:10,039 --> 00:27:14,191
+這個道理也就是做人的道理
+
+122
+00:27:14,239 --> 00:27:18,710
+任何一個人有了這個道理
+
+123
+00:27:18,759 --> 00:27:25,358
+才可以免去諸般痛苦
+好好的安居樂業
+
+124
+00:27:25,399 --> 00:27:29,950
+實實在在的過日子
+
+125
+00:27:34,680 --> 00:27:36,352
+反過來說
+
+126
+00:27:36,399 --> 00:27:40,108
+要是做人不曉得這個道理
+
+127
+00:27:40,159 --> 00:27:46,394
+就跟沉陷在苦海裡頭一樣
+一生一世
+
+128
+00:27:46,439 --> 00:27:52,628
+甚至於子孫孫,都得不到幸福
+
+129
+00:27:52,679 --> 00:27:55,671
+我為什麼要去取經
+
+130
+00:27:55,719 --> 00:28:01,316
+就是因為現在的人都陷在苦海裡了
+
+131
+00:28:01,359 --> 00:28:04,192
+要想成就這此些人
+
+132
+00:28:04,239 --> 00:28:12,510
+所以在大唐皇帝面前討下這
+重大繁難的差事
+
+133
+00:28:15,679 --> 00:28:17,829
+芭蕉扇借到了沒有
+
+134
+00:28:17,879 --> 00:28:19,517
+借來了
+
+135
+00:28:19,559 --> 00:28:22,790
+是不是這個
+
+136
+00:28:22,839 --> 00:28:27,993
+諸位施主,現在扇子既然借到了
+
+137
+00:28:28,039 --> 00:28:32,157
+貧僧師徒就要告辭了
+
+138
+00:28:32,199 --> 00:28:34,040
+慢一點
+
+139
+00:28:34,040 --> 00:28:39,797
+諸位,我想留聖僧在這兒多住幾天
+
+140
+00:28:39,839 --> 00:28:41,352
+好不好啊
+
+141
+00:28:41,399 --> 00:28:43,469
+好的,好的
+
+142
+00:28:43,519 --> 00:28:45,908
+謝謝諸位的好意
+
+143
+00:28:45,959 --> 00:28:51,795
+我早走一步就是早一步完成
+我們的任務
+
+144
+00:28:51,839 --> 00:28:56,196
+那麼就請令高徒先到火焰山
+
+145
+00:28:56,239 --> 00:29:02,155
+扇滅了火之後,再陪聖僧同行
+
+146
+00:29:02,199 --> 00:29:05,475
+好,你就去吧
+
+147
+00:30:24,479 --> 00:30:30,039
+鐵扇公主真可惡,拿假的芭蕉扇
+來騙我
+
+148
+00:30:30,039 --> 00:30:32,792
+我非殺了她不可
+
+149
+00:30:32,839 --> 00:30:36,309
+不,殺了她也是枉然
+
+150
+00:30:36,359 --> 00:30:39,590
+我素來不願意你多殺人
+
+151
+00:30:39,639 --> 00:30:42,995
+我們再想辦法
+
+152
+00:30:52,159 --> 00:30:56,232
+師兄,怎麼你也會上她的當
+
+153
+00:30:56,279 --> 00:30:58,554
+費了這麼許多的力氣
+
+154
+00:30:58,599 --> 00:31:02,114
+卻弄了一把假的扇子來
+
+155
+00:31:02,159 --> 00:31:06,516
+笑話,笑話
+
+156
+00:31:08,919 --> 00:31:10,432
+那麼你去
+
+157
+00:31:10,479 --> 00:31:14,392
+好好,我去我去,我就去
+
+158
+00:31:14,439 --> 00:31:17,033
+我去找牛魔王
+
+159
+00:31:17,119 --> 00:31:19,952
+這倒是一個好辦法
+
+160
+00:31:21,399 --> 00:31:24,550
+師兄,你看好不好
+
+161
+00:31:24,599 --> 00:31:27,397
+好,看你的了
+
+162
+00:33:07,199 --> 00:33:11,159
+你看我今天化妝得好嗎
+
+163
+00:33:11,159 --> 00:33:13,798
+好極了,我的小寶貝
+
+164
+00:33:13,839 --> 00:33:17,070
+你陪我到洞外頭去走走,好不好
+
+165
+00:33:17,119 --> 00:33:21,556
+我的寶貝,還是你一個人去吧
+
+166
+00:33:21,599 --> 00:33:24,830
+本來嘛,我們這種草婆子
+
+167
+00:33:24,879 --> 00:33:28,030
+跟你出去了會使你丟臉的
+
+168
+00:33:28,079 --> 00:33:32,039
+小寶貝,這是什麼話呢
+
+169
+00:33:32,039 --> 00:33:37,511
+你先去,我隨後就來好不好
+
+170
+00:35:28,039 --> 00:35:35,673
+女菩薩,你真是天仙下凡
+
+171
+00:35:35,719 --> 00:35:37,914
+你…你是什麼人
+
+172
+00:35:37,959 --> 00:35:41,474
+我是從芭蕉洞來找牛魔王的
+
+173
+00:35:41,520 --> 00:35:43,988
+快放手
+
+174
+00:35:49,559 --> 00:35:52,949
+女菩薩,你慢點走
+
+175
+00:36:44,239 --> 00:36:49,233
+小寶貝,誰來欺負你
+
+176
+00:36:49,279 --> 00:36:50,837
+是你
+
+177
+00:36:50,879 --> 00:36:54,349
+我哪裡捨得欺負你呢
+
+178
+00:36:56,919 --> 00:36:59,274
+你還是回芭蕉洞去吧
+
+179
+00:36:59,320 --> 00:37:01,709
+省得那個不要臉的東西
+
+180
+00:37:01,759 --> 00:37:07,675
+時常派人來請你,欺負我
+
+181
+00:37:07,719 --> 00:37:11,075
+你說有人來找我
+
+182
+00:37:11,119 --> 00:37:15,078
+外邊有一個豬臉的和尚來請你
+
+183
+00:37:15,120 --> 00:37:18,510
+差一點把我嚇死了
+
+184
+00:37:18,559 --> 00:37:22,757
+真有這回事嗎?待我出去看一看
+
+185
+00:37:50,679 --> 00:37:53,796
+牛大哥
+
+186
+00:37:53,839 --> 00:37:58,151
+這裡頭有個頂漂亮的小娘們
+
+187
+00:37:58,200 --> 00:38:03,991
+呸,那是我的女人,你為什麼要欺負她
+
+188
+00:38:04,039 --> 00:38:08,559
+大哥,我不知那就是二嫂,請原瓊
+
+189
+00:38:08,559 --> 00:38:11,949
+不知道不見罪,好啊,你走啊
+
+190
+00:38:11,999 --> 00:38:16,117
+不不不,我還有事情請大哥幫忙
+
+191
+00:38:18,479 --> 00:38:24,719
+小弟保唐僧取經,路過火焰山
+
+192
+00:38:24,719 --> 00:38:27,313
+請大哥跟嫂子說一聲
+
+193
+00:38:27,359 --> 00:38:30,829
+把這個芭蕉扇借來用一用
+
+194
+00:38:30,880 --> 00:38:33,519
+不成,那唐僧和孫悟空
+
+195
+00:38:33,519 --> 00:38:35,191
+是我孩子的仇人
+
+196
+00:38:35,239 --> 00:38:38,754
+我正要抓他們報仇
+
+197
+00:38:38,799 --> 00:38:44,988
+令郎已成正果,請大哥不必再計較吧
+
+198
+00:38:45,039 --> 00:38:48,952
+好,看在我們從前的交情
+我不跟你計較
+
+199
+00:38:49,000 --> 00:38:51,719
+那麼去吧
+
+200
+00:39:38,399 --> 00:39:44,190
+寶貝,那個豬臉和尚
+是我從前一個朋友
+
+201
+00:39:44,239 --> 00:39:46,514
+並不是芭蕉洞派來的
+
+202
+00:39:46,559 --> 00:39:47,753
+我不相信
+
+203
+00:39:47,799 --> 00:39:50,950
+我不騙你
+
+204
+00:39:50,999 --> 00:39:54,036
+現在那個和尚到哪兒去了呢
+
+205
+00:39:54,119 --> 00:39:57,794
+已經被我打走了
+
+206
+00:43:58,639 --> 00:44:01,358
+大王回來了
+
+207
+00:44:01,399 --> 00:44:02,388
+奶奶呢
+
+208
+00:44:02,439 --> 00:44:04,794
+在裡邊
+
+209
+00:44:42,999 --> 00:44:48,232
+今天是什麼風會把大王吹到這兒來的
+
+210
+00:44:48,279 --> 00:44:52,272
+聽到孫悟空保唐僧快到這兒
+
+211
+00:44:52,320 --> 00:44:56,916
+恐怕他要來借芭蕉扇過火焰山
+
+212
+00:44:56,959 --> 00:45:00,872
+那猴子是害我們兒子的仇人
+
+213
+00:45:00,919 --> 00:45:08,507
+早晚來了抓著他,讓我們夫妻出出恨
+
+214
+00:45:08,559 --> 00:45:12,711
+夫人,你為什麼哭
+
+215
+00:45:12,759 --> 00:45:15,717
+那猴子已經來過了
+
+216
+00:45:15,759 --> 00:45:18,876
+是我不肯把扇子借給他
+
+217
+00:45:18,919 --> 00:45:22,275
+不知道怎麼會跑到我的肚子裡來
+
+218
+00:45:22,319 --> 00:45:25,516
+弄得我肚子痛得要命
+
+219
+00:45:25,559 --> 00:45:31,399
+後來我沒有法子,只好把扇子借給他
+
+220
+00:45:31,399 --> 00:45:38,271
+可惜可惜,你怎麼把扇子借給他
+
+221
+00:45:38,320 --> 00:45:40,470
+拿去的是假的
+
+222
+00:45:40,519 --> 00:45:43,033
+假的
+
+223
+00:46:14,199 --> 00:46:19,876
+開筵慶祝大王歸
+
+224
+00:46:19,919 --> 00:46:25,630
+好酒殷勤勸幾杯
+
+225
+00:46:25,679 --> 00:46:34,189
+雞又香,鴨又美,豬又肥
+
+226
+00:46:34,240 --> 00:46:45,674
+我盡量的歌,我盡量的舞
+
+227
+00:46:45,719 --> 00:46:54,514
+你也要盡量的醉
+
+228
+00:47:03,599 --> 00:47:16,399
+大王啊,你把舊人丟
+
+229
+00:47:16,439 --> 00:47:22,628
+你愛新人媚
+
+230
+00:47:22,679 --> 00:47:36,673
+為你淌了多少相思淚
+
+231
+00:47:46,719 --> 00:47:55,718
+等一會燈兒吹帳兒垂
+
+232
+00:47:55,759 --> 00:48:00,879
+你獨自兒睡
+
+233
+00:48:00,879 --> 00:48:05,519
+也嘗嘗這個淒涼味
+
+234
+00:48:05,519 --> 00:48:13,437
+恕我不奉陪
+
+235
+00:48:18,559 --> 00:48:24,634
+就是同床
+
+236
+00:48:24,679 --> 00:48:34,350
+我們各人蓋著各人的被
+
+237
+00:48:38,399 --> 00:48:42,392
+大王,我醉了
+
+238
+00:48:55,079 --> 00:48:58,151
+夫人,那真扇子你放在什麼地方
+
+239
+00:48:58,199 --> 00:49:05,469
+那猴子花樣很多,而且那豬八戒
+本事更大
+
+240
+00:49:05,519 --> 00:49:09,797
+當心給他們騙了去
+
+241
+00:49:18,360 --> 00:49:21,989
+寶貝不是在這兒嗎
+
+242
+00:49:31,439 --> 00:49:39,319
+大王,你出神想什麼呢?
+還是收了吧
+
+243
+00:49:39,319 --> 00:49:43,551
+小寶貝
+
+244
+00:49:43,599 --> 00:49:49,037
+寶貝,你多喝一杯,你喝啊
+
+245
+00:49:53,919 --> 00:49:59,519
+今兒晚上,金龍大王
+還要請我去喝酒呢
+
+246
+00:49:59,519 --> 00:50:01,430
+那你就該去了
+
+247
+00:50:01,479 --> 00:50:02,878
+是的
+
+248
+00:50:02,919 --> 00:50:06,628
+你去替爺爺把金睛獸牽出去預備好
+
+249
+00:50:06,679 --> 00:50:08,271
+是
+
+250
+00:50:08,320 --> 00:50:12,598
+可是,你今兒個晚上去要少喝一點兒
+
+251
+00:50:12,639 --> 00:50:15,756
+免得回來睡著叫不醒你
+
+252
+00:50:15,800 --> 00:50:19,110
+不好了,爺爺那個金隋獸不見了
+
+253
+00:50:19,159 --> 00:50:20,911
+你們全都是死人嗎
+
+254
+00:50:20,959 --> 00:50:24,039
+家裡頭的東西怎麼會不見了呢
+
+255
+00:50:24,039 --> 00:50:27,918
+寶貝,不要管他們吧
+
+256
+00:50:27,960 --> 00:50:31,714
+恐怕是那豬八戒偷了去了
+
+257
+00:50:31,759 --> 00:50:35,274
+說不定我要到芭蕉洞去一趟
+
+258
+00:50:35,320 --> 00:50:39,313
+原來是你們做好了的圈套
+
+259
+00:50:42,280 --> 00:50:48,150
+你還是要到那個不要臉的女人那兒去
+
+260
+00:50:48,199 --> 00:50:50,713
+好寶貝,你不要哭了
+
+261
+00:50:50,759 --> 00:50:54,069
+我去去就來的
+
+262
+00:51:02,679 --> 00:51:07,309
+來來,喝喝
+
+263
+00:51:10,359 --> 00:51:12,475
+我現在放心了
+
+264
+00:51:12,519 --> 00:51:16,717
+不怕他們偷我們的寶貝
+
+265
+00:51:16,759 --> 00:51:21,310
+他們就是偷了去
+不知道把那絲線一拉
+
+266
+00:51:21,360 --> 00:51:26,275
+單是一顆珠子也沒有用處啊
+
+267
+00:51:26,319 --> 00:51:31,791
+是不是那麼一拉就變成扇子
+
+268
+00:51:35,120 --> 00:51:38,078
+大王,你今天喝醉了
+
+269
+00:51:38,119 --> 00:51:44,035
+自己的寶貝都忘了,還來問我
+
+270
+00:51:49,999 --> 00:51:53,708
+娘子,你看看我是誰
+
+271
+00:52:00,320 --> 00:52:03,756
+你是什麼人
+
+272
+00:52:03,799 --> 00:52:09,908
+我是唐僧的二徒弟,豬八戒
+
+273
+00:52:09,959 --> 00:52:14,794
+對不住,謝謝你,打擾了
+
+274
+00:52:19,080 --> 00:52:21,719
+再見
+
+275
+00:53:06,839 --> 00:53:10,718
+牛大嫂太風騷
+
+276
+00:53:10,760 --> 00:53:14,719
+眾小妖都俊俏
+
+277
+00:53:14,759 --> 00:53:24,828
+老豬真有點受不了
+
+278
+00:53:24,879 --> 00:53:28,872
+心機巧,手段妙
+
+279
+00:53:28,919 --> 00:53:32,832
+居然騙得了無價寶
+
+280
+00:53:32,880 --> 00:53:36,793
+這一番勞苦功高
+
+281
+00:53:36,839 --> 00:53:38,318
+沙僧該拜倒
+
+282
+00:53:38,359 --> 00:53:40,748
+猴兒該領教
+
+283
+00:53:40,799 --> 00:53:45,236
+師父也要嚇一跳
+
+284
+00:53:45,280 --> 00:53:49,193
+我老豬也有今朝
+
+285
+00:53:49,239 --> 00:53:54,359
+我老豬也有今朝
+
+286
+00:54:36,720 --> 00:54:40,474
+呆子,事情辦得怎麼樣了
+
+287
+00:54:40,519 --> 00:54:42,828
+不僅扇子到手
+
+288
+00:54:42,880 --> 00:54:48,796
+鐵扇公主並且還做了我
+半天的老婆
+
+289
+00:54:48,839 --> 00:54:51,717
+這倒便宜了你了
+
+290
+00:54:58,159 --> 00:55:01,595
+扇子拿來給我看看
+
+291
+00:55:16,039 --> 00:55:20,237
+你怎麼會把它縮小了的呀
+
+292
+00:55:40,559 --> 00:55:45,349
+老豬,你可認識我嗎
+
+293
+00:55:45,399 --> 00:55:49,187
+你不要跟我開玩笑了
+
+294
+00:55:49,239 --> 00:55:52,151
+誰跟你開玩笑
+
+295
+00:56:42,879 --> 00:56:45,393
+呆子,你去了怎麼樣
+
+296
+00:56:45,439 --> 00:56:47,111
+白跑了一趟
+
+297
+00:56:47,159 --> 00:56:49,992
+悟能,扇子借來沒有
+
+298
+00:56:50,039 --> 00:56:53,349
+我去找牛魔王,他不肯借
+
+299
+00:56:53,400 --> 00:56:59,191
+後來,我又變成老牛的樣子
+
+300
+00:56:59,239 --> 00:57:03,551
+在鐵扇公主那兒把扇子已經騙過來了
+
+301
+00:57:03,599 --> 00:57:10,599
+誰知道他又變成你的樣子又給他騙回去了
+
+302
+00:57:10,599 --> 00:57:12,749
+老牛的本領大
+
+303
+00:57:12,800 --> 00:57:16,156
+我還被他揍了一頓呢
+
+304
+00:57:16,199 --> 00:57:21,398
+呆子,你能辦這樣大的事那
+還算是呆子嗎
+
+305
+00:57:21,439 --> 00:57:25,671
+事情不都環在你頭上
+
+306
+00:57:30,759 --> 00:57:34,388
+你們不要吵了,趕緊再想辦法
+
+307
+00:57:34,439 --> 00:57:40,275
+哪一方…沒…沒有火啊
+
+308
+00:57:40,320 --> 00:57:47,078
+東南西北,只有西方有火
+
+309
+00:57:47,120 --> 00:57:50,749
+那我們不是要走回去了嗎
+
+310
+00:57:50,799 --> 00:57:52,949
+這路不通,不回去怎麼樣呢
+
+311
+00:57:52,999 --> 00:57:55,229
+八戒,你不要這樣說
+
+312
+00:57:55,279 --> 00:57:59,158
+要成功一件事情總是有阻礙的
+
+313
+00:57:59,199 --> 00:58:04,557
+我們要做這樣神聖的事情
+就要堅定我們的信念
+
+314
+00:58:04,599 --> 00:58:09,229
+不能因為有一點兒困難
+就中適改變我們的宗旨
+
+315
+00:58:09,280 --> 00:58:14,593
+你們這次失敗的原因是由於
+既不同心又不合力
+
+316
+00:58:14,639 --> 00:58:17,153
+假使你們三個人一條心
+
+317
+00:58:17,199 --> 00:58:20,509
+合起力量,共同跟牛魔王決鬥
+
+318
+00:58:20,559 --> 00:58:22,868
+事情一定可以成功的
+
+319
+00:58:22,919 --> 00:58:26,039
+我們謹遵師父的命令
+
+320
+00:58:26,039 --> 00:58:30,157
+去跟牛魔王爭一個誰勝誰敗
+
+321
+00:58:30,199 --> 00:58:34,272
+誰…誰…誰勝誰敗
+
+322
+00:58:34,320 --> 00:58:37,710
+那就好極了
+
+323
+00:58:37,759 --> 00:58:40,990
+各位受他的害處也不小了
+
+324
+00:58:41,040 --> 00:58:43,879
+希望各位也出此些力量
+
+325
+00:58:43,879 --> 00:58:49,590
+跟小徒們共同征服牛魔王,消滅火焰山
+
+326
+00:58:49,639 --> 00:58:53,837
+免除永遠的禍害
+
+327
+00:58:53,879 --> 00:58:57,508
+我們聽從師父的命令,為大家謀幸福
+
+328
+00:58:57,559 --> 00:58:58,878
+大家一起出力去
+
+329
+00:58:58,919 --> 00:59:01,035
+好
+
+330
+01:08:23,239 --> 01:08:25,628
+奶奶,不好了
+
+331
+01:08:25,679 --> 01:08:30,799
+爺爺給人家抓住了,你快點去看看吧
+
+332
+01:08:54,479 --> 01:08:56,709
+還不過來打,過來打
+
+333
+01:08:56,760 --> 01:08:59,718
+慢一點,慢一點
+
+334
+01:08:59,760 --> 01:09:05,790
+孽畜,只要你把扇子交出來,饒你不死
+
+335
+01:09:05,840 --> 01:09:12,757
+老牛,扇子在什麼地方?快拿出來啊
+
+336
+01:09:12,799 --> 01:09:19,352
+在我老…老婆那兒
+
+337
+01:09:25,240 --> 01:09:27,993
+夫人,夫人,夫人
+
+338
+01:09:28,039 --> 01:09:32,271
+你快點來救救我
+
+339
+01:09:32,320 --> 01:09:35,118
+把扇子拿出來吧
+
+340
+01:09:35,159 --> 01:09:39,630
+大王,好,好的
+
+341
+01:09:43,400 --> 01:09:47,234
+悟空,你再去一趟吧
+
index 04168a6..0852d36 100644 (file)
-1\r
-00:00:01,080 --> 00:00:09,070\r
-Princess Iron Fan\r
-\r
-2\r
-00:02:03,109 --> 00:02:09,280\r
-Journey to the West is a wonderful children's story,\r
-\r
-3\r
-00:02:09,280 --> 00:02:15,280\r
-but the world often misunderstands it as a fantasy novel.\r
-\r
-4\r
-00:02:15,280 --> 00:02:19,240\r
-This film was made for the purpose of\r
-\r
-5\r
-00:02:19,240 --> 00:02:24,240\r
-training the hearts and minds of children.\r
-\r
-6\r
-00:02:24,240 --> 00:02:29,280\r
-The story is pure, untainted by fantasy.\r
-\r
-7\r
-00:02:29,280 --> 00:02:32,560\r
-Fiery Mountain blocking the path of Tang Seng's company\r
-\r
-8\r
-00:02:32,560 --> 00:02:41,039\r
-is a metaphor for the difficulties in life.\r
-\r
-9\r
-00:02:41,039 --> 00:02:46,439\r
-In order to overcome them, one must keep faith.\r
-Everybody must work together\r
-\r
-10\r
-00:02:46,439 --> 00:02:52,430\r
-in order to obtain the palm leaf fan and put out the flames.\r
-\r
-11\r
-00:02:52,839 --> 00:02:58,178\r
-Tripikata True Sutra\r
-\r
-12\r
-00:03:34,479 --> 00:03:37,789\r
-It's already autumn, how can it still be so warm?\r
-\r
-13\r
-00:03:37,840 --> 00:03:42,349\r
-Fool, don't talk rubbish. We should hurry and get on our way.\r
-\r
-14\r
-00:04:06,919 --> 00:04:09,349\r
-Wukong, where is this place?\r
-\r
-15\r
-00:04:09,400 --> 00:04:13,669\r
-We must pass through here to continue westwards, that much is certain.\r
-\r
-16\r
-00:04:13,719 --> 00:04:18,110\r
-Might we have taken the wrong path?\r
-\r
-17\r
-00:04:18,149 --> 00:04:21,700\r
-Why is it so hot here?\r
-\r
-18\r
-00:04:30,029 --> 00:04:31,649\r
-Master, look!\r
-\r
-19\r
-00:04:31,650 --> 00:04:33,779\r
-Isn't that a house up ahead?\r
-\r
-20\r
-00:04:33,829 --> 00:04:38,100\r
-Let's go in and rest for a while, OK?\r
-\r
-21\r
-00:04:59,389 --> 00:05:02,899\r
-This place is called Fiery Mountain.\r
-\r
-22\r
-00:05:02,949 --> 00:05:06,019\r
-The fire stretches for hundreds of miles.\r
-\r
-23\r
-00:05:06,069 --> 00:05:08,740\r
-Not single straw of grass can grow here.\r
-\r
-24\r
-00:05:08,790 --> 00:05:11,620\r
-The four seasons of the year are all warm.\r
-\r
-25\r
-00:05:11,680 --> 00:05:19,629\r
-You couldn't pass through the mountain even with a head of copper and arms of iron.\r
-\r
-26\r
-00:05:19,670 --> 00:05:23,579\r
-What kind of place is this? Master, don't worry!\r
-\r
-27\r
-00:05:23,629 --> 00:05:27,139\r
-The three of us are all strong enough to pass!\r
-\r
-28\r
-00:05:27,189 --> 00:05:30,699\r
-Master, I'll go and have a look!\r
-\r
-29\r
-00:08:06,310 --> 00:08:09,579\r
-Wukong, what was it like?\r
-\r
-30\r
-00:08:09,629 --> 00:08:11,819\r
-Bad, bad, very bad.\r
-\r
-31\r
-00:08:11,879 --> 00:08:15,910\r
-If I were any slower the fur on my tail would have been burned off.\r
-\r
-32\r
-00:08:42,720 --> 00:08:47,600\r
-Noble host, the fires here are so big.\r
-\r
-33\r
-00:08:47,600 --> 00:08:49,669\r
-How can you grow any crops?\r
-\r
-34\r
-00:08:49,710 --> 00:08:53,980\r
-A thousand miles from here lives Princess Iron Fan.\r
-\r
-35\r
-00:08:54,039 --> 00:08:56,500\r
-She has a palm leaf fan.\r
-\r
-36\r
-00:08:56,559 --> 00:08:59,070\r
-Wave the fan once and the fire goes out.\r
-\r
-37\r
-00:08:59,120 --> 00:09:01,629\r
-Twice and the wind starts blowing.\r
-\r
-38\r
-00:09:01,679 --> 00:09:03,980\r
-Three times and the rain starts coming down.\r
-\r
-39\r
-00:09:04,039 --> 00:09:07,509\r
-In the following period we plant and harvest.\r
-\r
-40\r
-00:09:07,559 --> 00:09:11,340\r
-However, asking that princess to come\r
-\r
-41\r
-00:09:11,399 --> 00:09:14,870\r
-is certainly no simple matter.\r
-\r
-42\r
-00:09:14,909 --> 00:09:16,820\r
-Where does she live?\r
-\r
-43\r
-00:09:16,879 --> 00:09:20,190\r
-She lives in Palm Leaf Cave at Emerald Cloud Mountain.\r
-\r
-44\r
-00:09:20,240 --> 00:09:23,669\r
-Does she live there alone?\r
-\r
-45\r
-00:09:23,720 --> 00:09:25,750\r
-Doesn't she have a husband?\r
-\r
-46\r
-00:09:25,799 --> 00:09:29,580\r
-Her husband is Bull Demon King.\r
-\r
-47\r
-00:09:29,639 --> 00:09:32,200\r
-What, her husband is Old Bull?\r
-\r
-48\r
-00:09:32,240 --> 00:09:36,789\r
-Fool, you know him? Come with me to borrow the fan!\r
-\r
-49\r
-00:09:36,840 --> 00:09:41,750\r
-Actually... Old Bull doesn't live there.\r
-\r
-50\r
-00:09:41,799 --> 00:09:46,350\r
-Looking for his woman when he isn't home\r
-\r
-51\r
-00:09:46,399 --> 00:09:51,519\r
-isn't very... appropriate.\r
-\r
-52\r
-00:09:51,559 --> 00:09:58,309\r
-You... you... the two of you go.\r
-\r
-53\r
-00:09:58,360 --> 00:10:04,290\r
-I... I'll stay here and serve Master.\r
-\r
-54\r
-00:10:04,440 --> 00:10:11,269\r
-Sha Wujing, go with your two fellow apprentices.\r
-\r
-55\r
-00:10:38,571 --> 00:10:44,978\r
-Palm Leaf Cave\r
-\r
-56\r
-00:10:47,200 --> 00:10:51,549\r
-Fool, I always go first.\r
-\r
-57\r
-00:10:51,600 --> 00:10:54,350\r
-This time it's your turn!\r
-\r
-58\r
-00:10:58,519 --> 00:11:04,909\r
-Junior! I always go first, this time it's your turn!\r
-\r
-59\r
-00:11:04,960 --> 00:11:06,830\r
-Senior...\r
-\r
-60\r
-00:11:06,879 --> 00:11:10,990\r
-I'm asking you to make a small effort for Master. Can't you do that?\r
-\r
-61\r
-00:11:11,039 --> 00:11:14,309\r
-Hurry up!\r
-\r
-62\r
-00:11:39,639 --> 00:11:43,039\r
-Simple monk, where did you come from?\r
-\r
-63\r
-00:11:43,039 --> 00:11:49,870\r
-The Great Sage... Tang Seng... wants your princess...\r
-\r
-64\r
-00:11:49,919 --> 00:11:52,480\r
-Nonsense!\r
-\r
-65\r
-00:12:47,549 --> 00:12:52,059\r
-Senior... why don't you go instead?\r
-\r
-66\r
-00:12:52,120 --> 00:12:56,950\r
-Fool, you go!\r
-\r
-67\r
-00:12:57,000 --> 00:13:00,700\r
-Senior, why don't you go?\r
-\r
-68\r
-00:13:04,029 --> 00:13:07,460\r
-Lazy fool!\r
-\r
-69\r
-00:13:54,279 --> 00:13:57,899\r
-Great God of Thunder! Don't kill me, let me go!\r
-\r
-70\r
-00:13:57,960 --> 00:13:59,950\r
-Go tell your princess\r
-\r
-71\r
-00:14:00,000 --> 00:14:03,279\r
-that Sun Wukong has come to borrow the fan.\r
-\r
-72\r
-00:14:03,279 --> 00:14:08,399\r
-Yes, yes! Let me loose, I'll go at once.\r
-\r
-73\r
-00:14:29,559 --> 00:14:37,059\r
-Grandma, there's a Sun Wukong outside asking to borrow the fan.\r
-\r
-74\r
-00:14:41,519 --> 00:14:44,149\r
-Quickly fetch my sword.\r
-\r
-75\r
-00:15:01,639 --> 00:15:04,149\r
-Sun Wukong, you hurt my son!\r
-\r
-76\r
-00:15:04,200 --> 00:15:08,549\r
-You dare come here to meet your death?\r
-\r
-77\r
-00:15:08,600 --> 00:15:12,039\r
-I've never met you before, how could I have harmed your son?\r
-\r
-78\r
-00:15:12,039 --> 00:15:15,789\r
-My son Red Child's life was ruined, wasn't that your doing?\r
-\r
-79\r
-00:15:15,840 --> 00:15:20,389\r
-Your son is with the Goddess of Mercy now, how can you say that I hurt him?\r
-\r
-80\r
-00:15:20,440 --> 00:15:23,750\r
-Enough rubbish! Come here and let me chop you with my sword.\r
-\r
-81\r
-00:15:23,799 --> 00:15:26,149\r
-If you can take it I'll lend you the fan.\r
-\r
-82\r
-00:15:26,200 --> 00:15:28,549\r
-Really?\r
-\r
-83\r
-00:15:56,799 --> 00:16:00,629\r
-Stop! Quickly give me the fan!\r
-\r
-84\r
-00:17:53,630 --> 00:18:00,099\r
-Great Sage, weren't you going west? Why have you come back here?\r
-\r
-85\r
-00:18:11,150 --> 00:18:17,140\r
-Princess Iron Fan blew me here with a single wave of her fan.\r
-\r
-86\r
-00:18:17,190 --> 00:18:23,859\r
-That's truly amazing, Great Sage. I have something for you.\r
-\r
-87\r
-00:18:28,509 --> 00:18:33,450\r
-This is a wind pearl. When you use it,\r
-\r
-88\r
-00:18:33,509 --> 00:18:36,140\r
-your heart will become steady as a rock.\r
-\r
-89\r
-00:18:36,190 --> 00:18:39,180\r
-Princess Iron Fan won't be able to move you.\r
-\r
-90\r
-00:18:39,230 --> 00:18:42,849\r
-Great Sage, come and have a look.\r
-\r
-91\r
-00:19:00,430 --> 00:19:02,539\r
-Thank you.\r
-\r
-92\r
-00:19:06,069 --> 00:19:12,299\r
-Senior... where...\r
-\r
-93\r
-00:19:12,349 --> 00:19:18,690\r
-where has he... been blown to?\r
-\r
-94\r
-00:19:18,750 --> 00:19:26,099\r
-Who cares about him? Let the monkey handle himself. Let's go.\r
-\r
-95\r
-00:19:35,190 --> 00:19:37,259\r
-Senior... senior...\r
-\r
-96\r
-00:19:37,309 --> 00:19:43,470\r
-You... you...\r
-\r
-97\r
-00:19:43,470 --> 00:19:50,220\r
-Where were you blown to by that old lady?\r
-\r
-98\r
-00:19:50,269 --> 00:19:57,180\r
-Fool, now it's definitely your turn to go.\r
-\r
-99\r
-00:19:57,230 --> 00:20:00,930\r
-I'm not going, a single wave of her fan\r
-\r
-100\r
-00:20:00,990 --> 00:20:03,450\r
-could blow me to some faraway land.\r
-\r
-101\r
-00:20:03,509 --> 00:20:09,710\r
-Maybe it's better if you go again.\r
-\r
-102\r
-00:20:09,710 --> 00:20:12,220\r
-I won't go.\r
-\r
-103\r
-00:20:17,789 --> 00:20:22,779\r
-Next time I won't let you off!\r
-\r
-104\r
-00:20:56,150 --> 00:21:00,140\r
-This time I won't move no matter how much you wave,\r
-\r
-105\r
-00:21:00,190 --> 00:21:05,210\r
-as sure as I call myself am a man!\r
-\r
-106\r
-00:21:33,670 --> 00:21:38,579\r
-Senior, how come this time her fan couldn't move you?\r
-\r
-107\r
-00:21:46,829 --> 00:21:50,099\r
-Let's break our way in.\r
-\r
-108\r
-00:23:59,630 --> 00:24:04,180\r
-Quickly bring out the fan for Sun Wukong!\r
-\r
-109\r
-00:24:14,869 --> 00:24:16,900\r
-Sun Wukong, where are you?\r
-\r
-110\r
-00:24:16,950 --> 00:24:19,980\r
-I'm in your stomach!\r
-\r
-111\r
-00:24:45,750 --> 00:24:48,539\r
-Sun Wukong, spare me!\r
-\r
-112\r
-00:24:48,589 --> 00:24:51,180\r
-Only if you give me the fan!\r
-\r
-113\r
-00:24:51,230 --> 00:24:56,539\r
-I promise, I'll give it to you. Please come out!\r
-\r
-114\r
-00:25:00,230 --> 00:25:02,819\r
-Hurry up and bring the fan.\r
-\r
-115\r
-00:25:07,430 --> 00:25:09,220\r
-We've brought out the fan.\r
-\r
-116\r
-00:25:09,279 --> 00:25:12,069\r
-Why haven't you come out?\r
-\r
-117\r
-00:25:12,109 --> 00:25:16,619\r
-Open your mouth and I'll come out.\r
-\r
-118\r
-00:25:25,349 --> 00:25:29,420\r
-Sun Wukong, why haven't you come out?\r
-\r
-119\r
-00:25:50,349 --> 00:25:55,579\r
-Here I am. Lend me the fan for a while, I'll return it.\r
-\r
-120\r
-00:26:32,549 --> 00:26:36,579\r
-Master has been waiting long enough, let's get going!\r
-\r
-121\r
-00:27:01,869 --> 00:27:04,900\r
-Scripture, what is scripture?\r
-\r
-122\r
-00:27:04,950 --> 00:27:10,029\r
-Scriptures are the principles that link heaven and earth.\r
-\r
-123\r
-00:27:10,029 --> 00:27:14,180\r
-They are the principles of man.\r
-\r
-124\r
-00:27:14,230 --> 00:27:18,700\r
-Only he who holds these principles\r
-\r
-125\r
-00:27:18,750 --> 00:27:25,339\r
-can rid himself of pain and live a good life,\r
-\r
-126\r
-00:27:25,390 --> 00:27:29,940\r
-live a true and honest life.\r
-\r
-127\r
-00:27:34,680 --> 00:27:36,349\r
-Conversely,\r
-\r
-128\r
-00:27:36,390 --> 00:27:40,089\r
-he who does not know these principles,\r
-\r
-129\r
-00:27:40,150 --> 00:27:46,380\r
-will live a life full of misery.\r
-\r
-130\r
-00:27:46,430 --> 00:27:52,609\r
-Even his son or grandson will not achieve happiness.\r
-\r
-131\r
-00:27:52,670 --> 00:27:55,660\r
-Why am I going to get the scripture?\r
-\r
-132\r
-00:27:55,710 --> 00:28:01,299\r
-Because men nowadays are trapped in misery.\r
-\r
-133\r
-00:28:01,349 --> 00:28:04,180\r
-In order to achieve this goal, we are going to\r
-\r
-134\r
-00:28:04,230 --> 00:28:12,500\r
-appear before the Tang emperor and discuss this very complicated matter.\r
-\r
-135\r
-00:28:15,670 --> 00:28:17,819\r
-Did you get the palm leaf fan?\r
-\r
-136\r
-00:28:17,869 --> 00:28:19,400\r
-We have it.\r
-\r
-137\r
-00:28:19,401 --> 00:28:20,779\r
-Is this it?\r
-\r
-138\r
-00:28:22,829 --> 00:28:27,980\r
-Noble hosts, now that we have the fan,\r
-\r
-139\r
-00:28:28,029 --> 00:28:32,140\r
-we will take our leave.\r
-\r
-140\r
-00:28:32,190 --> 00:28:34,039\r
-Hold on.\r
-\r
-141\r
-00:28:34,039 --> 00:28:39,789\r
-Everyone, I would like to ask Sage Seng to stay here for a few more days.\r
-\r
-142\r
-00:28:39,829 --> 00:28:41,339\r
-Do you agree?\r
-\r
-143\r
-00:28:41,390 --> 00:28:43,460\r
-Agreed!\r
-\r
-144\r
-00:28:43,509 --> 00:28:45,890\r
-Thank you for your kindness.\r
-\r
-145\r
-00:28:45,950 --> 00:28:51,779\r
-But the sooner I leave the sooner we can complete our task.\r
-\r
-146\r
-00:28:51,829 --> 00:28:56,180\r
-Very well, will the honorable apprentice first go to Fiery Mountain.\r
-\r
-147\r
-00:28:56,230 --> 00:29:02,140\r
-After extinguishing the flames, continue to follow Sage Seng.\r
-\r
-148\r
-00:29:02,190 --> 00:29:05,460\r
-All right, go ahead!\r
-\r
-149\r
-00:30:24,470 --> 00:30:30,029\r
-Princess Iron Fan is really despicable, she gave us a fake fan!\r
-\r
-150\r
-00:30:30,029 --> 00:30:32,779\r
-I'll kill her for sure!\r
-\r
-151\r
-00:30:32,829 --> 00:30:36,299\r
-No, killing her is the wrong thing to do.\r
-\r
-152\r
-00:30:36,349 --> 00:30:39,579\r
-I won't let you kill anyone.\r
-\r
-153\r
-00:30:39,630 --> 00:30:42,980\r
-Let's think of something else.\r
-\r
-154\r
-00:30:52,150 --> 00:30:56,220\r
-Senior, how could you be fooled by her?\r
-\r
-155\r
-00:30:56,269 --> 00:30:58,539\r
-After making such an effort\r
-\r
-156\r
-00:30:58,589 --> 00:31:02,099\r
-all we got was a fake fan.\r
-\r
-157\r
-00:31:02,150 --> 00:31:06,500\r
-Ridiculous, ridiculous.\r
-\r
-158\r
-00:31:08,910 --> 00:31:10,420\r
-Then you go!\r
-\r
-159\r
-00:31:10,470 --> 00:31:14,380\r
-OK, I'll go, I'll go, I'm going!\r
-\r
-160\r
-00:31:14,430 --> 00:31:16,908\r
-I'll go find Bull Demon King.\r
-\r
-161\r
-00:31:16,909 --> 00:31:19,940\r
-This is a good solution.\r
-\r
-162\r
-00:31:21,390 --> 00:31:24,439\r
-Partner, what do you think?\r
-\r
-163\r
-00:31:24,440 --> 00:31:27,380\r
-We'll see how you do.\r
-\r
-164\r
-00:33:07,190 --> 00:33:11,150\r
-What do you think, am I pretty today?\r
-\r
-165\r
-00:33:11,150 --> 00:33:13,779\r
-Beautiful, my baby.\r
-\r
-166\r
-00:33:13,829 --> 00:33:17,059\r
-Accompany me for a walk outside the cave, all right?\r
-\r
-167\r
-00:33:17,109 --> 00:33:21,539\r
-My baby, why don't you go by yourself.\r
-\r
-168\r
-00:33:21,589 --> 00:33:24,819\r
-Why of course, I'm just a plain country girl.\r
-\r
-169\r
-00:33:24,869 --> 00:33:28,019\r
-Taking me outside might cause you to lose face.\r
-\r
-170\r
-00:33:28,069 --> 00:33:32,029\r
-Baby, what are you saying?\r
-\r
-171\r
-00:33:32,029 --> 00:33:37,500\r
-You go ahead, I'll come out in a while, all right?\r
-\r
-172\r
-00:33:39,852 --> 00:33:44,557\r
-Emerald Cloud Cave\r
-\r
-173\r
-00:35:28,030 --> 00:35:35,659\r
-Goddess, you're truly an angel come down from heaven.\r
-\r
-174\r
-00:35:35,710 --> 00:35:37,900\r
-Who... who are you?\r
-\r
-175\r
-00:35:37,949 --> 00:35:41,460\r
-I've come from Palm Leaf Cave to look for Bull Demon King.\r
-\r
-176\r
-00:35:41,519 --> 00:35:43,980\r
-Let go of me!\r
-\r
-177\r
-00:35:49,550 --> 00:35:52,940\r
-Goddess, slow down!\r
-\r
-178\r
-00:36:38,768 --> 00:36:40,133\r
-Emerald Cloud Cave\r
-\r
-179\r
-00:36:44,230 --> 00:36:49,219\r
-Baby, who has bullied you?\r
-\r
-180\r
-00:36:49,269 --> 00:36:50,820\r
-You!\r
-\r
-181\r
-00:36:50,869 --> 00:36:54,340\r
-How could I bully you?\r
-\r
-182\r
-00:36:56,909 --> 00:36:59,260\r
-Why don't you go back to Palm Leaf Cave?\r
-\r
-183\r
-00:36:59,320 --> 00:37:01,699\r
-It would spare you some embarrassment.\r
-\r
-184\r
-00:37:01,750 --> 00:37:07,659\r
-They often send people to look for you, and bully me.\r
-\r
-185\r
-00:37:07,710 --> 00:37:11,059\r
-Has there been someone here to look for me?\r
-\r
-186\r
-00:37:11,110 --> 00:37:15,059\r
-There's a pig monk outside looking for you.\r
-\r
-187\r
-00:37:15,119 --> 00:37:18,510\r
-He almost scared me to death.\r
-\r
-188\r
-00:37:18,550 --> 00:37:22,739\r
-How can this be? Wait while I go out to have a look.\r
-\r
-189\r
-00:37:50,670 --> 00:37:53,780\r
-Bull, old friend!\r
-\r
-190\r
-00:37:53,829 --> 00:37:58,139\r
-There's a very beautiful young lady in here.\r
-\r
-191\r
-00:37:58,199 --> 00:38:03,889\r
-Hey, that's my woman! Why have you come to bother her?\r
-\r
-192\r
-00:38:03,930 --> 00:38:08,550\r
-Oh, I didn't know, please forgive me!\r
-\r
-193\r
-00:38:08,550 --> 00:38:11,940\r
-You didn't know, so I can't blame you. Off you go!\r
-\r
-194\r
-00:38:11,989 --> 00:38:16,099\r
-No, no. I still have something I need you to help me with.\r
-\r
-195\r
-00:38:18,469 --> 00:38:24,710\r
-We were on our way to retrieve the scriptures when we arrived at Fiery Mountain.\r
-\r
-196\r
-00:38:24,710 --> 00:38:27,300\r
-Please ask your wife\r
-\r
-197\r
-00:38:27,349 --> 00:38:30,820\r
-to lend us the palm leaf fan for a while.\r
-\r
-198\r
-00:38:30,880 --> 00:38:33,510\r
-Absolutely not! Tang Seng and Sun Wukong\r
-\r
-199\r
-00:38:33,510 --> 00:38:35,179\r
-are my son's enemies.\r
-\r
-200\r
-00:38:35,230 --> 00:38:38,739\r
-I'd love to take my revenge on them.\r
-\r
-201\r
-00:38:38,789 --> 00:38:44,969\r
-Your son is with the Goddess of Mercy now, please don't fight.\r
-\r
-202\r
-00:38:45,030 --> 00:38:48,940\r
-All right, since we are old friends, I won't fight you.\r
-\r
-203\r
-00:38:49,000 --> 00:38:51,710\r
-Now go away!\r
-\r
-204\r
-00:39:38,389 --> 00:39:44,179\r
-Baby, that pig monk is a friend of mine.\r
-\r
-205\r
-00:39:44,230 --> 00:39:46,500\r
-He wasn't sent from Palm Leaf Cave at all.\r
-\r
-206\r
-00:39:46,550 --> 00:39:47,739\r
-I don't believe you.\r
-\r
-207\r
-00:39:47,789 --> 00:39:50,940\r
-I'm not lying to you!\r
-\r
-208\r
-00:39:50,989 --> 00:39:54,019\r
-Where is that monk now?\r
-\r
-209\r
-00:39:54,110 --> 00:39:57,780\r
-I've already scared him away.\r
-\r
-210\r
-00:43:34,814 --> 00:43:40,987\r
-Palm Leaf Cave\r
-\r
-211\r
-00:43:58,630 --> 00:44:01,340\r
-The king has returned!\r
-\r
-212\r
-00:44:01,389 --> 00:44:02,369\r
-Where's grandma?\r
-\r
-213\r
-00:44:02,429 --> 00:44:04,780\r
-She's inside.\r
-\r
-214\r
-00:44:42,989 --> 00:44:48,219\r
-By what honor has the king come to visit today?\r
-\r
-215\r
-00:44:48,269 --> 00:44:52,260\r
-I heard that Sun Wukong and Tang Seng are coming here.\r
-\r
-216\r
-00:44:52,320 --> 00:44:56,909\r
-I'm afraid they want to use the palm leaf fan to pass Fiery Mountain.\r
-\r
-217\r
-00:44:56,949 --> 00:45:00,860\r
-That monkey is the one who harmed our son.\r
-\r
-218\r
-00:45:00,909 --> 00:45:08,489\r
-I'll get him sooner or later, we will have our revenge.\r
-\r
-219\r
-00:45:08,550 --> 00:45:12,699\r
-Darling, why are you crying?\r
-\r
-220\r
-00:45:12,750 --> 00:45:15,699\r
-That monkey has already been here.\r
-\r
-221\r
-00:45:15,750 --> 00:45:18,860\r
-I refused to give him the fan.\r
-\r
-222\r
-00:45:18,909 --> 00:45:22,260\r
-I don't know how, but he got inside my stomach.\r
-\r
-223\r
-00:45:22,309 --> 00:45:25,500\r
-It hurt so bad I thought I would die.\r
-\r
-224\r
-00:45:25,550 --> 00:45:30,589\r
-At last I had no choice but to give him the fan.\r
-\r
-225\r
-00:45:30,789 --> 00:45:35,260\r
-That's terrible, how could you give him the fan?\r
-\r
-226\r
-00:45:38,320 --> 00:45:40,469\r
-I gave him a false one.\r
-\r
-227\r
-00:45:40,720 --> 00:45:43,019\r
-A false one?\r
-\r
-228\r
-00:46:14,190 --> 00:46:19,860\r
-A banquet to celebrate the king's return\r
-\r
-229\r
-00:46:19,909 --> 00:46:25,619\r
-Please drink the fine wine.\r
-\r
-230\r
-00:46:25,670 --> 00:46:34,179\r
-The chicken is fragrant, the duck is beautiful, and the pig is fat.\r
-\r
-231\r
-00:46:34,239 --> 00:46:45,670\r
-I try my best to sing, I try my best to dance.\r
-\r
-232\r
-00:46:45,710 --> 00:46:54,500\r
-You must also try your best to drink.\r
-\r
-233\r
-00:47:03,590 --> 00:47:16,389\r
-My king! You dumped the old one.\r
-\r
-234\r
-00:47:16,429 --> 00:47:22,610\r
-You love another woman.\r
-\r
-235\r
-00:47:22,670 --> 00:47:34,659\r
-Countless tears were spilled for you.\r
-\r
-236\r
-00:47:46,710 --> 00:47:55,699\r
-When the light is out and the curtain is dropped,\r
-\r
-237\r
-00:47:55,750 --> 00:48:00,869\r
-you will sleep alone.\r
-\r
-238\r
-00:48:00,869 --> 00:48:05,510\r
-You too will taste loneliness.\r
-\r
-239\r
-00:48:05,510 --> 00:48:13,420\r
-Pardon me for not making you company.\r
-\r
-240\r
-00:48:18,550 --> 00:48:24,619\r
-Even if we are on the same bed,\r
-\r
-241\r
-00:48:24,670 --> 00:48:34,340\r
-we will sleep under separate sheets.\r
-\r
-242\r
-00:48:38,389 --> 00:48:42,380\r
-King, I'm drunk.\r
-\r
-243\r
-00:48:55,070 --> 00:48:58,139\r
-Darling, where did you put the real fan?\r
-\r
-244\r
-00:48:58,190 --> 00:49:05,460\r
-That monkey is very deceitful, and the pig has even greater skill.\r
-\r
-245\r
-00:49:05,510 --> 00:49:09,780\r
-If you're not careful they might trick you.\r
-\r
-246\r
-00:49:18,360 --> 00:49:21,980\r
-Our treasure is right here.\r
-\r
-247\r
-00:49:31,429 --> 00:49:39,309\r
-King, what are you thinking about? Why don't you take it?\r
-\r
-248\r
-00:49:39,309 --> 00:49:40,847\r
-My treasure.\r
-\r
-249\r
-00:49:41,514 --> 00:49:44,150\r
-Emerald Cloud Cave\r
-\r
-250\r
-00:49:44,250 --> 00:49:49,019\r
-Baby, have another cup. Drink.\r
-\r
-251\r
-00:49:53,909 --> 00:49:59,510\r
-Gold Dragon King has asked me to drink with him tonight\r
-\r
-252\r
-00:49:59,510 --> 00:50:01,420\r
-Then you should go.\r
-\r
-253\r
-00:50:01,469 --> 00:50:02,860\r
-That's right.\r
-\r
-254\r
-00:50:02,909 --> 00:50:06,610\r
-You should prepare the golden eyed beast for grandpa.\r
-\r
-255\r
-00:50:06,670 --> 00:50:08,260\r
-I will.\r
-\r
-256\r
-00:50:08,320 --> 00:50:12,590\r
-You should drink a little less tonight.\r
-\r
-257\r
-00:50:12,630 --> 00:50:15,739\r
-Otherwise I won't be able to wake you up.\r
-\r
-258\r
-00:50:15,800 --> 00:50:19,110\r
-It's terrible, grandpa's golden eyed beast has disappeared!\r
-\r
-259\r
-00:50:19,150 --> 00:50:20,900\r
-Are you all deaf and blind?\r
-\r
-260\r
-00:50:20,949 --> 00:50:24,030\r
-How could it just disappear?\r
-\r
-261\r
-00:50:24,030 --> 00:50:27,900\r
-Baby, don't mind them.\r
-\r
-262\r
-00:50:27,960 --> 00:50:31,710\r
-I'm afraid Zhu Bajie might have stolen it.\r
-\r
-263\r
-00:50:31,750 --> 00:50:35,260\r
-Maybe I should go over to Palm Leaf Cave.\r
-\r
-264\r
-00:50:35,320 --> 00:50:39,309\r
-What? You've had this planned all along.\r
-\r
-265\r
-00:50:42,280 --> 00:50:48,150\r
-You still want to go over to that shameless woman?\r
-\r
-266\r
-00:50:48,190 --> 00:50:50,699\r
-Please baby, don't cry.\r
-\r
-267\r
-00:50:50,750 --> 00:50:54,059\r
-I'll be back soon.\r
-\r
-268\r
-00:50:57,624 --> 00:51:01,194\r
-Palm Leaf Cave\r
-\r
-269\r
-00:51:02,670 --> 00:51:07,300\r
-Come over here, drink a little!\r
-\r
-270\r
-00:51:10,349 --> 00:51:12,460\r
-Now I can relax.\r
-\r
-271\r
-00:51:12,510 --> 00:51:16,699\r
-We don't have to worry about our treasure being stolen.\r
-\r
-272\r
-00:51:16,750 --> 00:51:21,300\r
-Even if they stole it, they wouldn't know to pull the silk thread.\r
-\r
-273\r
-00:51:21,360 --> 00:51:26,269\r
-Having just a pearl won't be of any use.\r
-\r
-274\r
-00:51:26,309 --> 00:51:31,780\r
-Pulling the thread will turn it into a fan, right?\r
-\r
-275\r
-00:51:35,119 --> 00:51:38,070\r
-King, you're drunk.\r
-\r
-276\r
-00:51:38,110 --> 00:51:44,019\r
-You forgot about your own treasure, and are asking me.\r
-\r
-277\r
-00:51:49,989 --> 00:51:53,690\r
-Lady, look at who I am.\r
-\r
-278\r
-00:52:00,320 --> 00:52:03,750\r
-Who are you?\r
-\r
-279\r
-00:52:03,789 --> 00:52:09,889\r
-I am Tang Seng's second apprentice, Zhu Bajie.\r
-\r
-280\r
-00:52:09,949 --> 00:52:14,780\r
-Sorry about bothering you, and thanks!\r
-\r
-281\r
-00:52:19,079 --> 00:52:21,710\r
-Bye!\r
-\r
-282\r
-00:53:06,829 --> 00:53:10,699\r
-Bull's wife is too flirtatious.\r
-\r
-283\r
-00:53:10,760 --> 00:53:14,710\r
-All her underlings are handsome.\r
-\r
-284\r
-00:53:14,750 --> 00:53:24,809\r
-Old Pig almost couldn't take it.\r
-\r
-285\r
-00:53:24,869 --> 00:53:28,860\r
-Using clever tricks and tactics,\r
-\r
-286\r
-00:53:28,909 --> 00:53:32,820\r
-I stole their treasure away.\r
-\r
-287\r
-00:53:32,880 --> 00:53:36,789\r
-This is a great accomplishment.\r
-\r
-288\r
-00:53:36,829 --> 00:53:38,300\r
-Sandy should be on his knees.\r
-\r
-289\r
-00:53:38,349 --> 00:53:40,730\r
-Monkey should learn from me.\r
-\r
-290\r
-00:53:40,789 --> 00:53:45,219\r
-Even Master will be astonished.\r
-\r
-291\r
-00:53:45,280 --> 00:53:49,190\r
-Old Pig is truly masterful.\r
-\r
-292\r
-00:53:49,230 --> 00:53:54,349\r
-Old Pig is truly masterful.\r
-\r
-293\r
-00:54:36,719 --> 00:54:40,469\r
-Fool, how are things going?\r
-\r
-294\r
-00:54:40,510 --> 00:54:42,809\r
-Not only did I get the fan,\r
-\r
-295\r
-00:54:42,880 --> 00:54:48,789\r
-Princess Iron Fan was my wife for half a day, too.\r
-\r
-296\r
-00:54:48,829 --> 00:54:51,699\r
-You got a good deal.\r
-\r
-297\r
-00:54:58,150 --> 00:55:01,579\r
-Hey, let me see the fan.\r
-\r
-298\r
-00:55:16,030 --> 00:55:20,219\r
-Why did you shrink it?\r
-\r
-299\r
-00:55:40,550 --> 00:55:45,340\r
-Old Pig, you do recognize me, right?\r
-\r
-300\r
-00:55:45,389 --> 00:55:49,170\r
-Stop joking around with me.\r
-\r
-301\r
-00:55:49,230 --> 00:55:52,139\r
-Who's joking around with you?\r
-\r
-302\r
-00:56:42,869 --> 00:56:45,380\r
-Fool, how did it go?\r
-\r
-303\r
-00:56:45,429 --> 00:56:47,099\r
-It was all for nothing.\r
-\r
-304\r
-00:56:47,150 --> 00:56:49,980\r
-Wuneng, did you borrow the fan?\r
-\r
-305\r
-00:56:50,030 --> 00:56:53,340\r
-I found Bull Demon King, but he refused.\r
-\r
-306\r
-00:56:53,400 --> 00:56:59,190\r
-Then, I turned into his look-alike.\r
-\r
-307\r
-00:56:59,230 --> 00:57:03,539\r
-I tricked Princess Iron Fan into giving me the fan.\r
-\r
-308\r
-00:57:03,590 --> 00:57:10,590\r
-But then Old Bull turned into your look-alike and tricked me into giving it back.\r
-\r
-309\r
-00:57:10,590 --> 00:57:12,739\r
-Old Bull's skills are great.\r
-\r
-310\r
-00:57:12,800 --> 00:57:16,150\r
-I got beaten up by him, too.\r
-\r
-311\r
-00:57:16,190 --> 00:57:21,380\r
-How could you get the fan and still be such a fool?\r
-\r
-312\r
-00:57:21,429 --> 00:57:25,659\r
-Not everything revolves around you!\r
-\r
-313\r
-00:57:30,750 --> 00:57:34,369\r
-Don't fight, we should quickly think of a solution.\r
-\r
-314\r
-00:57:34,429 --> 00:57:40,260\r
-In which... which direction is there no fire?\r
-\r
-315\r
-00:57:40,320 --> 00:57:47,070\r
-Of east, south, west, north, there's fire only to the west.\r
-\r
-316\r
-00:57:47,119 --> 00:57:50,739\r
-So we have no option but to go back.\r
-\r
-317\r
-00:57:50,789 --> 00:57:52,940\r
-This path is blocked, what other options do we have?\r
-\r
-318\r
-00:57:52,989 --> 00:57:55,219\r
-Bajie, don't talk like that.\r
-\r
-319\r
-00:57:55,269 --> 00:57:59,139\r
-There will always be obstacles in our path.\r
-\r
-320\r
-00:57:59,190 --> 00:58:04,539\r
-To complete our sacred task we must be strong in our faith.\r
-\r
-321\r
-00:58:04,590 --> 00:58:09,219\r
-We can't change our goal half way just because we encounter some obstacles.\r
-\r
-322\r
-00:58:09,280 --> 00:58:14,590\r
-The reason that we've been defeated is that we haven't worked together.\r
-\r
-323\r
-00:58:14,630 --> 00:58:17,139\r
-If the three of you work as one,\r
-\r
-324\r
-00:58:17,190 --> 00:58:20,500\r
-put your strength together to fight Bull Demon King,\r
-\r
-325\r
-00:58:20,550 --> 00:58:22,849\r
-then you will certainly be victorious.\r
-\r
-326\r
-00:58:22,909 --> 00:58:26,030\r
-We have heard the order of Master\r
-\r
-327\r
-00:58:26,030 --> 00:58:30,139\r
-and will fight Bull Demon King to the end.\r
-\r
-328\r
-00:58:30,190 --> 00:58:34,260\r
-to... to the end.\r
-\r
-329\r
-00:58:34,320 --> 00:58:37,710\r
-That's excellent!\r
-\r
-330\r
-00:58:37,750 --> 00:58:40,980\r
-We have all been through hardships.\r
-\r
-331\r
-00:58:41,039 --> 00:58:43,869\r
-I hope everyone will make an effort\r
-\r
-332\r
-00:58:43,869 --> 00:58:49,579\r
-together with my disciples to defeat Bull Demon King and put out the flames of Fiery Mountain.\r
-\r
-333\r
-00:58:49,630 --> 00:58:52,820\r
-Otherwise this misery will never end.\r
-\r
-334\r
-00:58:53,869 --> 00:58:57,489\r
-We have heard the order of Master, to seek happiness for all.\r
-\r
-335\r
-00:58:57,550 --> 00:58:58,860\r
-Everyone work together!\r
-\r
-336\r
-00:58:58,909 --> 00:59:00,519\r
-All right!\r
-\r
-337\r
-01:08:23,229 --> 01:08:25,609\r
-Grandma, it's terrible!\r
-\r
-338\r
-01:08:25,670 --> 01:08:30,789\r
-Grandpa has been trapped, come quickly and look!\r
-\r
-339\r
-01:08:54,470 --> 01:08:56,699\r
-The fight's not over yet, not over.\r
-\r
-340\r
-01:08:56,760 --> 01:08:58,710\r
-Careful, careful.\r
-\r
-341\r
-01:08:59,760 --> 01:09:05,789\r
-Beast, all you have to is give us the fan and we'll spare your life.\r
-\r
-342\r
-01:09:05,840 --> 01:09:12,750\r
-Old Bull, where is the fan? Hand it over!\r
-\r
-343\r
-01:09:12,789 --> 01:09:19,340\r
-My... my wife... has it.\r
-\r
-344\r
-01:09:25,239 --> 01:09:27,989\r
-Darling, darling!\r
-\r
-345\r
-01:09:28,029 --> 01:09:32,260\r
-Save me, hurry!\r
-\r
-346\r
-01:09:32,319 --> 01:09:35,109\r
-Give them the fan.\r
-\r
-347\r
-01:09:35,149 --> 01:09:39,619\r
-King! All right, all right!\r
-\r
-348\r
-01:09:43,399 --> 01:09:47,229\r
-Wukong, you go one more time!\r
-\r
-349\r
-01:12:30,850 --> 01:12:46,599\r
-The End\r
+1
+00:00:01,080 --> 00:00:09,070
+Princess Iron Fan
+
+2
+00:02:03,109 --> 00:02:09,280
+Journey to the West is a wonderful children's story,
+
+3
+00:02:09,280 --> 00:02:15,280
+but the world often misunderstands it as a fantasy novel.
+
+4
+00:02:15,280 --> 00:02:19,240
+This film was made for the purpose of
+
+5
+00:02:19,240 --> 00:02:24,240
+training the hearts and minds of children.
+
+6
+00:02:24,240 --> 00:02:29,280
+The story is pure, untainted by fantasy.
+
+7
+00:02:29,280 --> 00:02:32,560
+Fiery Mountain blocking the path of Tang Seng's company
+
+8
+00:02:32,560 --> 00:02:41,039
+is a metaphor for the difficulties in life.
+
+9
+00:02:41,039 --> 00:02:46,439
+In order to overcome them, one must keep faith.
+Everybody must work together
+
+10
+00:02:46,439 --> 00:02:52,430
+in order to obtain the palm leaf fan and put out the flames.
+
+11
+00:02:52,839 --> 00:02:58,178
+Tripikata True Sutra
+
+12
+00:03:34,479 --> 00:03:37,789
+It's already autumn, how can it still be so warm?
+
+13
+00:03:37,840 --> 00:03:42,349
+Fool, don't talk rubbish. We should hurry and get on our way.
+
+14
+00:04:06,919 --> 00:04:09,349
+Wukong, where is this place?
+
+15
+00:04:09,400 --> 00:04:13,669
+We must pass through here to continue westwards, that much is certain.
+
+16
+00:04:13,719 --> 00:04:18,110
+Might we have taken the wrong path?
+
+17
+00:04:18,149 --> 00:04:21,700
+Why is it so hot here?
+
+18
+00:04:30,029 --> 00:04:31,649
+Master, look!
+
+19
+00:04:31,650 --> 00:04:33,779
+Isn't that a house up ahead?
+
+20
+00:04:33,829 --> 00:04:38,100
+Let's go in and rest for a while, OK?
+
+21
+00:04:59,389 --> 00:05:02,899
+This place is called Fiery Mountain.
+
+22
+00:05:02,949 --> 00:05:06,019
+The fire stretches for hundreds of miles.
+
+23
+00:05:06,069 --> 00:05:08,740
+Not single straw of grass can grow here.
+
+24
+00:05:08,790 --> 00:05:11,620
+The four seasons of the year are all warm.
+
+25
+00:05:11,680 --> 00:05:19,629
+You couldn't pass through the mountain even with a head of copper and arms of iron.
+
+26
+00:05:19,670 --> 00:05:23,579
+What kind of place is this? Master, don't worry!
+
+27
+00:05:23,629 --> 00:05:27,139
+The three of us are all strong enough to pass!
+
+28
+00:05:27,189 --> 00:05:30,699
+Master, I'll go and have a look!
+
+29
+00:08:06,310 --> 00:08:09,579
+Wukong, what was it like?
+
+30
+00:08:09,629 --> 00:08:11,819
+Bad, bad, very bad.
+
+31
+00:08:11,879 --> 00:08:15,910
+If I were any slower the fur on my tail would have been burned off.
+
+32
+00:08:42,720 --> 00:08:47,600
+Noble host, the fires here are so big.
+
+33
+00:08:47,600 --> 00:08:49,669
+How can you grow any crops?
+
+34
+00:08:49,710 --> 00:08:53,980
+A thousand miles from here lives Princess Iron Fan.
+
+35
+00:08:54,039 --> 00:08:56,500
+She has a palm leaf fan.
+
+36
+00:08:56,559 --> 00:08:59,070
+Wave the fan once and the fire goes out.
+
+37
+00:08:59,120 --> 00:09:01,629
+Twice and the wind starts blowing.
+
+38
+00:09:01,679 --> 00:09:03,980
+Three times and the rain starts coming down.
+
+39
+00:09:04,039 --> 00:09:07,509
+In the following period we plant and harvest.
+
+40
+00:09:07,559 --> 00:09:11,340
+However, asking that princess to come
+
+41
+00:09:11,399 --> 00:09:14,870
+is certainly no simple matter.
+
+42
+00:09:14,909 --> 00:09:16,820
+Where does she live?
+
+43
+00:09:16,879 --> 00:09:20,190
+She lives in Palm Leaf Cave at Emerald Cloud Mountain.
+
+44
+00:09:20,240 --> 00:09:23,669
+Does she live there alone?
+
+45
+00:09:23,720 --> 00:09:25,750
+Doesn't she have a husband?
+
+46
+00:09:25,799 --> 00:09:29,580
+Her husband is Bull Demon King.
+
+47
+00:09:29,639 --> 00:09:32,200
+What, her husband is Old Bull?
+
+48
+00:09:32,240 --> 00:09:36,789
+Fool, you know him? Come with me to borrow the fan!
+
+49
+00:09:36,840 --> 00:09:41,750
+Actually... Old Bull doesn't live there.
+
+50
+00:09:41,799 --> 00:09:46,350
+Looking for his woman when he isn't home
+
+51
+00:09:46,399 --> 00:09:51,519
+isn't very... appropriate.
+
+52
+00:09:51,559 --> 00:09:58,309
+You... you... the two of you go.
+
+53
+00:09:58,360 --> 00:10:04,290
+I... I'll stay here and serve Master.
+
+54
+00:10:04,440 --> 00:10:11,269
+Sha Wujing, go with your two fellow apprentices.
+
+55
+00:10:38,571 --> 00:10:44,978
+Palm Leaf Cave
+
+56
+00:10:47,200 --> 00:10:51,549
+Fool, I always go first.
+
+57
+00:10:51,600 --> 00:10:54,350
+This time it's your turn!
+
+58
+00:10:58,519 --> 00:11:04,909
+Junior! I always go first, this time it's your turn!
+
+59
+00:11:04,960 --> 00:11:06,830
+Senior...
+
+60
+00:11:06,879 --> 00:11:10,990
+I'm asking you to make a small effort for Master. Can't you do that?
+
+61
+00:11:11,039 --> 00:11:14,309
+Hurry up!
+
+62
+00:11:39,639 --> 00:11:43,039
+Simple monk, where did you come from?
+
+63
+00:11:43,039 --> 00:11:49,870
+The Great Sage... Tang Seng... wants your princess...
+
+64
+00:11:49,919 --> 00:11:52,480
+Nonsense!
+
+65
+00:12:47,549 --> 00:12:52,059
+Senior... why don't you go instead?
+
+66
+00:12:52,120 --> 00:12:56,950
+Fool, you go!
+
+67
+00:12:57,000 --> 00:13:00,700
+Senior, why don't you go?
+
+68
+00:13:04,029 --> 00:13:07,460
+Lazy fool!
+
+69
+00:13:54,279 --> 00:13:57,899
+Great God of Thunder! Don't kill me, let me go!
+
+70
+00:13:57,960 --> 00:13:59,950
+Go tell your princess
+
+71
+00:14:00,000 --> 00:14:03,279
+that Sun Wukong has come to borrow the fan.
+
+72
+00:14:03,279 --> 00:14:08,399
+Yes, yes! Let me loose, I'll go at once.
+
+73
+00:14:29,559 --> 00:14:37,059
+Grandma, there's a Sun Wukong outside asking to borrow the fan.
+
+74
+00:14:41,519 --> 00:14:44,149
+Quickly fetch my sword.
+
+75
+00:15:01,639 --> 00:15:04,149
+Sun Wukong, you hurt my son!
+
+76
+00:15:04,200 --> 00:15:08,549
+You dare come here to meet your death?
+
+77
+00:15:08,600 --> 00:15:12,039
+I've never met you before, how could I have harmed your son?
+
+78
+00:15:12,039 --> 00:15:15,789
+My son Red Child's life was ruined, wasn't that your doing?
+
+79
+00:15:15,840 --> 00:15:20,389
+Your son is with the Goddess of Mercy now, how can you say that I hurt him?
+
+80
+00:15:20,440 --> 00:15:23,750
+Enough rubbish! Come here and let me chop you with my sword.
+
+81
+00:15:23,799 --> 00:15:26,149
+If you can take it I'll lend you the fan.
+
+82
+00:15:26,200 --> 00:15:28,549
+Really?
+
+83
+00:15:56,799 --> 00:16:00,629
+Stop! Quickly give me the fan!
+
+84
+00:17:53,630 --> 00:18:00,099
+Great Sage, weren't you going west? Why have you come back here?
+
+85
+00:18:11,150 --> 00:18:17,140
+Princess Iron Fan blew me here with a single wave of her fan.
+
+86
+00:18:17,190 --> 00:18:23,859
+That's truly amazing, Great Sage. I have something for you.
+
+87
+00:18:28,509 --> 00:18:33,450
+This is a wind pearl. When you use it,
+
+88
+00:18:33,509 --> 00:18:36,140
+your heart will become steady as a rock.
+
+89
+00:18:36,190 --> 00:18:39,180
+Princess Iron Fan won't be able to move you.
+
+90
+00:18:39,230 --> 00:18:42,849
+Great Sage, come and have a look.
+
+91
+00:19:00,430 --> 00:19:02,539
+Thank you.
+
+92
+00:19:06,069 --> 00:19:12,299
+Senior... where...
+
+93
+00:19:12,349 --> 00:19:18,690
+where has he... been blown to?
+
+94
+00:19:18,750 --> 00:19:26,099
+Who cares about him? Let the monkey handle himself. Let's go.
+
+95
+00:19:35,190 --> 00:19:37,259
+Senior... senior...
+
+96
+00:19:37,309 --> 00:19:43,470
+You... you...
+
+97
+00:19:43,470 --> 00:19:50,220
+Where were you blown to by that old lady?
+
+98
+00:19:50,269 --> 00:19:57,180
+Fool, now it's definitely your turn to go.
+
+99
+00:19:57,230 --> 00:20:00,930
+I'm not going, a single wave of her fan
+
+100
+00:20:00,990 --> 00:20:03,450
+could blow me to some faraway land.
+
+101
+00:20:03,509 --> 00:20:09,710
+Maybe it's better if you go again.
+
+102
+00:20:09,710 --> 00:20:12,220
+I won't go.
+
+103
+00:20:17,789 --> 00:20:22,779
+Next time I won't let you off!
+
+104
+00:20:56,150 --> 00:21:00,140
+This time I won't move no matter how much you wave,
+
+105
+00:21:00,190 --> 00:21:05,210
+as sure as I call myself am a man!
+
+106
+00:21:33,670 --> 00:21:38,579
+Senior, how come this time her fan couldn't move you?
+
+107
+00:21:46,829 --> 00:21:50,099
+Let's break our way in.
+
+108
+00:23:59,630 --> 00:24:04,180
+Quickly bring out the fan for Sun Wukong!
+
+109
+00:24:14,869 --> 00:24:16,900
+Sun Wukong, where are you?
+
+110
+00:24:16,950 --> 00:24:19,980
+I'm in your stomach!
+
+111
+00:24:45,750 --> 00:24:48,539
+Sun Wukong, spare me!
+
+112
+00:24:48,589 --> 00:24:51,180
+Only if you give me the fan!
+
+113
+00:24:51,230 --> 00:24:56,539
+I promise, I'll give it to you. Please come out!
+
+114
+00:25:00,230 --> 00:25:02,819
+Hurry up and bring the fan.
+
+115
+00:25:07,430 --> 00:25:09,220
+We've brought out the fan.
+
+116
+00:25:09,279 --> 00:25:12,069
+Why haven't you come out?
+
+117
+00:25:12,109 --> 00:25:16,619
+Open your mouth and I'll come out.
+
+118
+00:25:25,349 --> 00:25:29,420
+Sun Wukong, why haven't you come out?
+
+119
+00:25:50,349 --> 00:25:55,579
+Here I am. Lend me the fan for a while, I'll return it.
+
+120
+00:26:32,549 --> 00:26:36,579
+Master has been waiting long enough, let's get going!
+
+121
+00:27:01,869 --> 00:27:04,900
+Scripture, what is scripture?
+
+122
+00:27:04,950 --> 00:27:10,029
+Scriptures are the principles that link heaven and earth.
+
+123
+00:27:10,029 --> 00:27:14,180
+They are the principles of man.
+
+124
+00:27:14,230 --> 00:27:18,700
+Only he who holds these principles
+
+125
+00:27:18,750 --> 00:27:25,339
+can rid himself of pain and live a good life,
+
+126
+00:27:25,390 --> 00:27:29,940
+live a true and honest life.
+
+127
+00:27:34,680 --> 00:27:36,349
+Conversely,
+
+128
+00:27:36,390 --> 00:27:40,089
+he who does not know these principles,
+
+129
+00:27:40,150 --> 00:27:46,380
+will live a life full of misery.
+
+130
+00:27:46,430 --> 00:27:52,609
+Even his son or grandson will not achieve happiness.
+
+131
+00:27:52,670 --> 00:27:55,660
+Why am I going to get the scripture?
+
+132
+00:27:55,710 --> 00:28:01,299
+Because men nowadays are trapped in misery.
+
+133
+00:28:01,349 --> 00:28:04,180
+In order to achieve this goal, we are going to
+
+134
+00:28:04,230 --> 00:28:12,500
+appear before the Tang emperor and discuss this very complicated matter.
+
+135
+00:28:15,670 --> 00:28:17,819
+Did you get the palm leaf fan?
+
+136
+00:28:17,869 --> 00:28:19,400
+We have it.
+
+137
+00:28:19,401 --> 00:28:20,779
+Is this it?
+
+138
+00:28:22,829 --> 00:28:27,980
+Noble hosts, now that we have the fan,
+
+139
+00:28:28,029 --> 00:28:32,140
+we will take our leave.
+
+140
+00:28:32,190 --> 00:28:34,039
+Hold on.
+
+141
+00:28:34,039 --> 00:28:39,789
+Everyone, I would like to ask Sage Seng to stay here for a few more days.
+
+142
+00:28:39,829 --> 00:28:41,339
+Do you agree?
+
+143
+00:28:41,390 --> 00:28:43,460
+Agreed!
+
+144
+00:28:43,509 --> 00:28:45,890
+Thank you for your kindness.
+
+145
+00:28:45,950 --> 00:28:51,779
+But the sooner I leave the sooner we can complete our task.
+
+146
+00:28:51,829 --> 00:28:56,180
+Very well, will the honorable apprentice first go to Fiery Mountain.
+
+147
+00:28:56,230 --> 00:29:02,140
+After extinguishing the flames, continue to follow Sage Seng.
+
+148
+00:29:02,190 --> 00:29:05,460
+All right, go ahead!
+
+149
+00:30:24,470 --> 00:30:30,029
+Princess Iron Fan is really despicable, she gave us a fake fan!
+
+150
+00:30:30,029 --> 00:30:32,779
+I'll kill her for sure!
+
+151
+00:30:32,829 --> 00:30:36,299
+No, killing her is the wrong thing to do.
+
+152
+00:30:36,349 --> 00:30:39,579
+I won't let you kill anyone.
+
+153
+00:30:39,630 --> 00:30:42,980
+Let's think of something else.
+
+154
+00:30:52,150 --> 00:30:56,220
+Senior, how could you be fooled by her?
+
+155
+00:30:56,269 --> 00:30:58,539
+After making such an effort
+
+156
+00:30:58,589 --> 00:31:02,099
+all we got was a fake fan.
+
+157
+00:31:02,150 --> 00:31:06,500
+Ridiculous, ridiculous.
+
+158
+00:31:08,910 --> 00:31:10,420
+Then you go!
+
+159
+00:31:10,470 --> 00:31:14,380
+OK, I'll go, I'll go, I'm going!
+
+160
+00:31:14,430 --> 00:31:16,908
+I'll go find Bull Demon King.
+
+161
+00:31:16,909 --> 00:31:19,940
+This is a good solution.
+
+162
+00:31:21,390 --> 00:31:24,439
+Partner, what do you think?
+
+163
+00:31:24,440 --> 00:31:27,380
+We'll see how you do.
+
+164
+00:33:07,190 --> 00:33:11,150
+What do you think, am I pretty today?
+
+165
+00:33:11,150 --> 00:33:13,779
+Beautiful, my baby.
+
+166
+00:33:13,829 --> 00:33:17,059
+Accompany me for a walk outside the cave, all right?
+
+167
+00:33:17,109 --> 00:33:21,539
+My baby, why don't you go by yourself.
+
+168
+00:33:21,589 --> 00:33:24,819
+Why of course, I'm just a plain country girl.
+
+169
+00:33:24,869 --> 00:33:28,019
+Taking me outside might cause you to lose face.
+
+170
+00:33:28,069 --> 00:33:32,029
+Baby, what are you saying?
+
+171
+00:33:32,029 --> 00:33:37,500
+You go ahead, I'll come out in a while, all right?
+
+172
+00:33:39,852 --> 00:33:44,557
+Emerald Cloud Cave
+
+173
+00:35:28,030 --> 00:35:35,659
+Goddess, you're truly an angel come down from heaven.
+
+174
+00:35:35,710 --> 00:35:37,900
+Who... who are you?
+
+175
+00:35:37,949 --> 00:35:41,460
+I've come from Palm Leaf Cave to look for Bull Demon King.
+
+176
+00:35:41,519 --> 00:35:43,980
+Let go of me!
+
+177
+00:35:49,550 --> 00:35:52,940
+Goddess, slow down!
+
+178
+00:36:38,768 --> 00:36:40,133
+Emerald Cloud Cave
+
+179
+00:36:44,230 --> 00:36:49,219
+Baby, who has bullied you?
+
+180
+00:36:49,269 --> 00:36:50,820
+You!
+
+181
+00:36:50,869 --> 00:36:54,340
+How could I bully you?
+
+182
+00:36:56,909 --> 00:36:59,260
+Why don't you go back to Palm Leaf Cave?
+
+183
+00:36:59,320 --> 00:37:01,699
+It would spare you some embarrassment.
+
+184
+00:37:01,750 --> 00:37:07,659
+They often send people to look for you, and bully me.
+
+185
+00:37:07,710 --> 00:37:11,059
+Has there been someone here to look for me?
+
+186
+00:37:11,110 --> 00:37:15,059
+There's a pig monk outside looking for you.
+
+187
+00:37:15,119 --> 00:37:18,510
+He almost scared me to death.
+
+188
+00:37:18,550 --> 00:37:22,739
+How can this be? Wait while I go out to have a look.
+
+189
+00:37:50,670 --> 00:37:53,780
+Bull, old friend!
+
+190
+00:37:53,829 --> 00:37:58,139
+There's a very beautiful young lady in here.
+
+191
+00:37:58,199 --> 00:38:03,889
+Hey, that's my woman! Why have you come to bother her?
+
+192
+00:38:03,930 --> 00:38:08,550
+Oh, I didn't know, please forgive me!
+
+193
+00:38:08,550 --> 00:38:11,940
+You didn't know, so I can't blame you. Off you go!
+
+194
+00:38:11,989 --> 00:38:16,099
+No, no. I still have something I need you to help me with.
+
+195
+00:38:18,469 --> 00:38:24,710
+We were on our way to retrieve the scriptures when we arrived at Fiery Mountain.
+
+196
+00:38:24,710 --> 00:38:27,300
+Please ask your wife
+
+197
+00:38:27,349 --> 00:38:30,820
+to lend us the palm leaf fan for a while.
+
+198
+00:38:30,880 --> 00:38:33,510
+Absolutely not! Tang Seng and Sun Wukong
+
+199
+00:38:33,510 --> 00:38:35,179
+are my son's enemies.
+
+200
+00:38:35,230 --> 00:38:38,739
+I'd love to take my revenge on them.
+
+201
+00:38:38,789 --> 00:38:44,969
+Your son is with the Goddess of Mercy now, please don't fight.
+
+202
+00:38:45,030 --> 00:38:48,940
+All right, since we are old friends, I won't fight you.
+
+203
+00:38:49,000 --> 00:38:51,710
+Now go away!
+
+204
+00:39:38,389 --> 00:39:44,179
+Baby, that pig monk is a friend of mine.
+
+205
+00:39:44,230 --> 00:39:46,500
+He wasn't sent from Palm Leaf Cave at all.
+
+206
+00:39:46,550 --> 00:39:47,739
+I don't believe you.
+
+207
+00:39:47,789 --> 00:39:50,940
+I'm not lying to you!
+
+208
+00:39:50,989 --> 00:39:54,019
+Where is that monk now?
+
+209
+00:39:54,110 --> 00:39:57,780
+I've already scared him away.
+
+210
+00:43:34,814 --> 00:43:40,987
+Palm Leaf Cave
+
+211
+00:43:58,630 --> 00:44:01,340
+The king has returned!
+
+212
+00:44:01,389 --> 00:44:02,369
+Where's grandma?
+
+213
+00:44:02,429 --> 00:44:04,780
+She's inside.
+
+214
+00:44:42,989 --> 00:44:48,219
+By what honor has the king come to visit today?
+
+215
+00:44:48,269 --> 00:44:52,260
+I heard that Sun Wukong and Tang Seng are coming here.
+
+216
+00:44:52,320 --> 00:44:56,909
+I'm afraid they want to use the palm leaf fan to pass Fiery Mountain.
+
+217
+00:44:56,949 --> 00:45:00,860
+That monkey is the one who harmed our son.
+
+218
+00:45:00,909 --> 00:45:08,489
+I'll get him sooner or later, we will have our revenge.
+
+219
+00:45:08,550 --> 00:45:12,699
+Darling, why are you crying?
+
+220
+00:45:12,750 --> 00:45:15,699
+That monkey has already been here.
+
+221
+00:45:15,750 --> 00:45:18,860
+I refused to give him the fan.
+
+222
+00:45:18,909 --> 00:45:22,260
+I don't know how, but he got inside my stomach.
+
+223
+00:45:22,309 --> 00:45:25,500
+It hurt so bad I thought I would die.
+
+224
+00:45:25,550 --> 00:45:30,589
+At last I had no choice but to give him the fan.
+
+225
+00:45:30,789 --> 00:45:35,260
+That's terrible, how could you give him the fan?
+
+226
+00:45:38,320 --> 00:45:40,469
+I gave him a false one.
+
+227
+00:45:40,720 --> 00:45:43,019
+A false one?
+
+228
+00:46:14,190 --> 00:46:19,860
+A banquet to celebrate the king's return
+
+229
+00:46:19,909 --> 00:46:25,619
+Please drink the fine wine.
+
+230
+00:46:25,670 --> 00:46:34,179
+The chicken is fragrant, the duck is beautiful, and the pig is fat.
+
+231
+00:46:34,239 --> 00:46:45,670
+I try my best to sing, I try my best to dance.
+
+232
+00:46:45,710 --> 00:46:54,500
+You must also try your best to drink.
+
+233
+00:47:03,590 --> 00:47:16,389
+My king! You dumped the old one.
+
+234
+00:47:16,429 --> 00:47:22,610
+You love another woman.
+
+235
+00:47:22,670 --> 00:47:34,659
+Countless tears were spilled for you.
+
+236
+00:47:46,710 --> 00:47:55,699
+When the light is out and the curtain is dropped,
+
+237
+00:47:55,750 --> 00:48:00,869
+you will sleep alone.
+
+238
+00:48:00,869 --> 00:48:05,510
+You too will taste loneliness.
+
+239
+00:48:05,510 --> 00:48:13,420
+Pardon me for not making you company.
+
+240
+00:48:18,550 --> 00:48:24,619
+Even if we are on the same bed,
+
+241
+00:48:24,670 --> 00:48:34,340
+we will sleep under separate sheets.
+
+242
+00:48:38,389 --> 00:48:42,380
+King, I'm drunk.
+
+243
+00:48:55,070 --> 00:48:58,139
+Darling, where did you put the real fan?
+
+244
+00:48:58,190 --> 00:49:05,460
+That monkey is very deceitful, and the pig has even greater skill.
+
+245
+00:49:05,510 --> 00:49:09,780
+If you're not careful they might trick you.
+
+246
+00:49:18,360 --> 00:49:21,980
+Our treasure is right here.
+
+247
+00:49:31,429 --> 00:49:39,309
+King, what are you thinking about? Why don't you take it?
+
+248
+00:49:39,309 --> 00:49:40,847
+My treasure.
+
+249
+00:49:41,514 --> 00:49:44,150
+Emerald Cloud Cave
+
+250
+00:49:44,250 --> 00:49:49,019
+Baby, have another cup. Drink.
+
+251
+00:49:53,909 --> 00:49:59,510
+Gold Dragon King has asked me to drink with him tonight
+
+252
+00:49:59,510 --> 00:50:01,420
+Then you should go.
+
+253
+00:50:01,469 --> 00:50:02,860
+That's right.
+
+254
+00:50:02,909 --> 00:50:06,610
+You should prepare the golden eyed beast for grandpa.
+
+255
+00:50:06,670 --> 00:50:08,260
+I will.
+
+256
+00:50:08,320 --> 00:50:12,590
+You should drink a little less tonight.
+
+257
+00:50:12,630 --> 00:50:15,739
+Otherwise I won't be able to wake you up.
+
+258
+00:50:15,800 --> 00:50:19,110
+It's terrible, grandpa's golden eyed beast has disappeared!
+
+259
+00:50:19,150 --> 00:50:20,900
+Are you all deaf and blind?
+
+260
+00:50:20,949 --> 00:50:24,030
+How could it just disappear?
+
+261
+00:50:24,030 --> 00:50:27,900
+Baby, don't mind them.
+
+262
+00:50:27,960 --> 00:50:31,710
+I'm afraid Zhu Bajie might have stolen it.
+
+263
+00:50:31,750 --> 00:50:35,260
+Maybe I should go over to Palm Leaf Cave.
+
+264
+00:50:35,320 --> 00:50:39,309
+What? You've had this planned all along.
+
+265
+00:50:42,280 --> 00:50:48,150
+You still want to go over to that shameless woman?
+
+266
+00:50:48,190 --> 00:50:50,699
+Please baby, don't cry.
+
+267
+00:50:50,750 --> 00:50:54,059
+I'll be back soon.
+
+268
+00:50:57,624 --> 00:51:01,194
+Palm Leaf Cave
+
+269
+00:51:02,670 --> 00:51:07,300
+Come over here, drink a little!
+
+270
+00:51:10,349 --> 00:51:12,460
+Now I can relax.
+
+271
+00:51:12,510 --> 00:51:16,699
+We don't have to worry about our treasure being stolen.
+
+272
+00:51:16,750 --> 00:51:21,300
+Even if they stole it, they wouldn't know to pull the silk thread.
+
+273
+00:51:21,360 --> 00:51:26,269
+Having just a pearl won't be of any use.
+
+274
+00:51:26,309 --> 00:51:31,780
+Pulling the thread will turn it into a fan, right?
+
+275
+00:51:35,119 --> 00:51:38,070
+King, you're drunk.
+
+276
+00:51:38,110 --> 00:51:44,019
+You forgot about your own treasure, and are asking me.
+
+277
+00:51:49,989 --> 00:51:53,690
+Lady, look at who I am.
+
+278
+00:52:00,320 --> 00:52:03,750
+Who are you?
+
+279
+00:52:03,789 --> 00:52:09,889
+I am Tang Seng's second apprentice, Zhu Bajie.
+
+280
+00:52:09,949 --> 00:52:14,780
+Sorry about bothering you, and thanks!
+
+281
+00:52:19,079 --> 00:52:21,710
+Bye!
+
+282
+00:53:06,829 --> 00:53:10,699
+Bull's wife is too flirtatious.
+
+283
+00:53:10,760 --> 00:53:14,710
+All her underlings are handsome.
+
+284
+00:53:14,750 --> 00:53:24,809
+Old Pig almost couldn't take it.
+
+285
+00:53:24,869 --> 00:53:28,860
+Using clever tricks and tactics,
+
+286
+00:53:28,909 --> 00:53:32,820
+I stole their treasure away.
+
+287
+00:53:32,880 --> 00:53:36,789
+This is a great accomplishment.
+
+288
+00:53:36,829 --> 00:53:38,300
+Sandy should be on his knees.
+
+289
+00:53:38,349 --> 00:53:40,730
+Monkey should learn from me.
+
+290
+00:53:40,789 --> 00:53:45,219
+Even Master will be astonished.
+
+291
+00:53:45,280 --> 00:53:49,190
+Old Pig is truly masterful.
+
+292
+00:53:49,230 --> 00:53:54,349
+Old Pig is truly masterful.
+
+293
+00:54:36,719 --> 00:54:40,469
+Fool, how are things going?
+
+294
+00:54:40,510 --> 00:54:42,809
+Not only did I get the fan,
+
+295
+00:54:42,880 --> 00:54:48,789
+Princess Iron Fan was my wife for half a day, too.
+
+296
+00:54:48,829 --> 00:54:51,699
+You got a good deal.
+
+297
+00:54:58,150 --> 00:55:01,579
+Hey, let me see the fan.
+
+298
+00:55:16,030 --> 00:55:20,219
+Why did you shrink it?
+
+299
+00:55:40,550 --> 00:55:45,340
+Old Pig, you do recognize me, right?
+
+300
+00:55:45,389 --> 00:55:49,170
+Stop joking around with me.
+
+301
+00:55:49,230 --> 00:55:52,139
+Who's joking around with you?
+
+302
+00:56:42,869 --> 00:56:45,380
+Fool, how did it go?
+
+303
+00:56:45,429 --> 00:56:47,099
+It was all for nothing.
+
+304
+00:56:47,150 --> 00:56:49,980
+Wuneng, did you borrow the fan?
+
+305
+00:56:50,030 --> 00:56:53,340
+I found Bull Demon King, but he refused.
+
+306
+00:56:53,400 --> 00:56:59,190
+Then, I turned into his look-alike.
+
+307
+00:56:59,230 --> 00:57:03,539
+I tricked Princess Iron Fan into giving me the fan.
+
+308
+00:57:03,590 --> 00:57:10,590
+But then Old Bull turned into your look-alike and tricked me into giving it back.
+
+309
+00:57:10,590 --> 00:57:12,739
+Old Bull's skills are great.
+
+310
+00:57:12,800 --> 00:57:16,150
+I got beaten up by him, too.
+
+311
+00:57:16,190 --> 00:57:21,380
+How could you get the fan and still be such a fool?
+
+312
+00:57:21,429 --> 00:57:25,659
+Not everything revolves around you!
+
+313
+00:57:30,750 --> 00:57:34,369
+Don't fight, we should quickly think of a solution.
+
+314
+00:57:34,429 --> 00:57:40,260
+In which... which direction is there no fire?
+
+315
+00:57:40,320 --> 00:57:47,070
+Of east, south, west, north, there's fire only to the west.
+
+316
+00:57:47,119 --> 00:57:50,739
+So we have no option but to go back.
+
+317
+00:57:50,789 --> 00:57:52,940
+This path is blocked, what other options do we have?
+
+318
+00:57:52,989 --> 00:57:55,219
+Bajie, don't talk like that.
+
+319
+00:57:55,269 --> 00:57:59,139
+There will always be obstacles in our path.
+
+320
+00:57:59,190 --> 00:58:04,539
+To complete our sacred task we must be strong in our faith.
+
+321
+00:58:04,590 --> 00:58:09,219
+We can't change our goal half way just because we encounter some obstacles.
+
+322
+00:58:09,280 --> 00:58:14,590
+The reason that we've been defeated is that we haven't worked together.
+
+323
+00:58:14,630 --> 00:58:17,139
+If the three of you work as one,
+
+324
+00:58:17,190 --> 00:58:20,500
+put your strength together to fight Bull Demon King,
+
+325
+00:58:20,550 --> 00:58:22,849
+then you will certainly be victorious.
+
+326
+00:58:22,909 --> 00:58:26,030
+We have heard the order of Master
+
+327
+00:58:26,030 --> 00:58:30,139
+and will fight Bull Demon King to the end.
+
+328
+00:58:30,190 --> 00:58:34,260
+to... to the end.
+
+329
+00:58:34,320 --> 00:58:37,710
+That's excellent!
+
+330
+00:58:37,750 --> 00:58:40,980
+We have all been through hardships.
+
+331
+00:58:41,039 --> 00:58:43,869
+I hope everyone will make an effort
+
+332
+00:58:43,869 --> 00:58:49,579
+together with my disciples to defeat Bull Demon King and put out the flames of Fiery Mountain.
+
+333
+00:58:49,630 --> 00:58:52,820
+Otherwise this misery will never end.
+
+334
+00:58:53,869 --> 00:58:57,489
+We have heard the order of Master, to seek happiness for all.
+
+335
+00:58:57,550 --> 00:58:58,860
+Everyone work together!
+
+336
+00:58:58,909 --> 00:59:00,519
+All right!
+
+337
+01:08:23,229 --> 01:08:25,609
+Grandma, it's terrible!
+
+338
+01:08:25,670 --> 01:08:30,789
+Grandpa has been trapped, come quickly and look!
+
+339
+01:08:54,470 --> 01:08:56,699
+The fight's not over yet, not over.
+
+340
+01:08:56,760 --> 01:08:58,710
+Careful, careful.
+
+341
+01:08:59,760 --> 01:09:05,789
+Beast, all you have to is give us the fan and we'll spare your life.
+
+342
+01:09:05,840 --> 01:09:12,750
+Old Bull, where is the fan? Hand it over!
+
+343
+01:09:12,789 --> 01:09:19,340
+My... my wife... has it.
+
+344
+01:09:25,239 --> 01:09:27,989
+Darling, darling!
+
+345
+01:09:28,029 --> 01:09:32,260
+Save me, hurry!
+
+346
+01:09:32,319 --> 01:09:35,109
+Give them the fan.
+
+347
+01:09:35,149 --> 01:09:39,619
+King! All right, all right!
+
+348
+01:09:43,399 --> 01:09:47,229
+Wukong, you go one more time!
+
+349
+01:12:30,850 --> 01:12:46,599
+The End
index 6adfcc9..e80b568 100644 (file)
-/**\r
- * --------------------------------------------------------------------\r
- * jQuery-Plugin "pngFix"\r
- * Version: 1.2, 09.03.2009\r
- * by Andreas Eberhard, andreas.eberhard@gmail.com\r
- *                      http://jquery.andreaseberhard.de/\r
- *\r
- * Copyright (c) 2007 Andreas Eberhard\r
- * Licensed under GPL (http://www.opensource.org/licenses/gpl-license.php)\r
- *\r
- * Changelog:\r
- *    09.03.2009 Version 1.2\r
- *    - Update for jQuery 1.3.x, removed @ from selectors\r
- *    11.09.2007 Version 1.1\r
- *    - removed noConflict\r
- *    - added png-support for input type=image\r
- *    - 01.08.2007 CSS background-image support extension added by Scott Jehl, scott@filamentgroup.com, http://www.filamentgroup.com\r
- *    31.05.2007 initial Version 1.0\r
- * --------------------------------------------------------------------\r
- * @example $(function(){$(document).pngFix();});\r
- * @desc Fixes all PNG's in the document on document.ready\r
- *\r
- * jQuery(function(){jQuery(document).pngFix();});\r
- * @desc Fixes all PNG's in the document on document.ready when using noConflict\r
- *\r
- * @example $(function(){$('div.examples').pngFix();});\r
- * @desc Fixes all PNG's within div with class examples\r
- *\r
- * @example $(function(){$('div.examples').pngFix( { blankgif:'ext.gif' } );});\r
- * @desc Fixes all PNG's within div with class examples, provides blank gif for input with png\r
- * --------------------------------------------------------------------\r
- */\r
-\r
-(function($) {\r
-\r
-jQuery.fn.pngFix = function(settings) {\r
-\r
-       // Settings\r
-       settings = jQuery.extend({\r
-               blankgif: 'blank.gif'\r
-       }, settings);\r
-\r
-       var ie55 = (navigator.appName == "Microsoft Internet Explorer" && parseInt(navigator.appVersion) == 4 && navigator.appVersion.indexOf("MSIE 5.5") != -1);\r
-       var ie6 = (navigator.appName == "Microsoft Internet Explorer" && parseInt(navigator.appVersion) == 4 && navigator.appVersion.indexOf("MSIE 6.0") != -1);\r
-\r
-       if (jQuery.browser.msie && (ie55 || ie6)) {\r
-\r
-               //fix images with png-source\r
-               jQuery(this).find("img[src$=.png]").each(function() {\r
-\r
-                       jQuery(this).attr('width',jQuery(this).width());\r
-                       jQuery(this).attr('height',jQuery(this).height());\r
-\r
-                       var prevStyle = '';\r
-                       var strNewHTML = '';\r
-                       var imgId = (jQuery(this).attr('id')) ? 'id="' + jQuery(this).attr('id') + '" ' : '';\r
-                       var imgClass = (jQuery(this).attr('class')) ? 'class="' + jQuery(this).attr('class') + '" ' : '';\r
-                       var imgTitle = (jQuery(this).attr('title')) ? 'title="' + jQuery(this).attr('title') + '" ' : '';\r
-                       var imgAlt = (jQuery(this).attr('alt')) ? 'alt="' + jQuery(this).attr('alt') + '" ' : '';\r
-                       var imgAlign = (jQuery(this).attr('align')) ? 'float:' + jQuery(this).attr('align') + ';' : '';\r
-                       var imgHand = (jQuery(this).parent().attr('href')) ? 'cursor:hand;' : '';\r
-                       if (this.style.border) {\r
-                               prevStyle += 'border:'+this.style.border+';';\r
-                               this.style.border = '';\r
-                       }\r
-                       if (this.style.padding) {\r
-                               prevStyle += 'padding:'+this.style.padding+';';\r
-                               this.style.padding = '';\r
-                       }\r
-                       if (this.style.margin) {\r
-                               prevStyle += 'margin:'+this.style.margin+';';\r
-                               this.style.margin = '';\r
-                       }\r
-                       var imgStyle = (this.style.cssText);\r
-\r
-                       strNewHTML += '<span '+imgId+imgClass+imgTitle+imgAlt;\r
-                       strNewHTML += 'style="position:relative;white-space:pre-line;display:inline-block;background:transparent;'+imgAlign+imgHand;\r
-                       strNewHTML += 'width:' + jQuery(this).width() + 'px;' + 'height:' + jQuery(this).height() + 'px;';\r
-                       strNewHTML += 'filter:progid:DXImageTransform.Microsoft.AlphaImageLoader' + '(src=\'' + jQuery(this).attr('src') + '\', sizingMethod=\'scale\');';\r
-                       strNewHTML += imgStyle+'"></span>';\r
-                       if (prevStyle != ''){\r
-                               strNewHTML = '<span style="position:relative;display:inline-block;'+prevStyle+imgHand+'width:' + jQuery(this).width() + 'px;' + 'height:' + jQuery(this).height() + 'px;'+'">' + strNewHTML + '</span>';\r
-                       }\r
-\r
-                       jQuery(this).hide();\r
-                       jQuery(this).after(strNewHTML);\r
-\r
-               });\r
-\r
-               // fix css background pngs\r
-               jQuery(this).find("*").each(function(){\r
-                       var bgIMG = jQuery(this).css('background-image');\r
-                       if(bgIMG.indexOf(".png")!=-1){\r
-                               var iebg = bgIMG.split('url("')[1].split('")')[0];\r
-                               jQuery(this).css('background-image', 'none');\r
-                               jQuery(this).get(0).runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + iebg + "',sizingMethod='scale')";\r
-                       }\r
-               });\r
-               \r
-               //fix input with png-source\r
-               jQuery(this).find("input[src$=.png]").each(function() {\r
-                       var bgIMG = jQuery(this).attr('src');\r
-                       jQuery(this).get(0).runtimeStyle.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader' + '(src=\'' + bgIMG + '\', sizingMethod=\'scale\');';\r
-               jQuery(this).attr('src', settings.blankgif)\r
-               });\r
-       \r
-       }\r
-       \r
-       return jQuery;\r
-\r
-};\r
-\r
-})(jQuery);\r
+/**
+ * --------------------------------------------------------------------
+ * jQuery-Plugin "pngFix"
+ * Version: 1.2, 09.03.2009
+ * by Andreas Eberhard, andreas.eberhard@gmail.com
+ *                      http://jquery.andreaseberhard.de/
+ *
+ * Copyright (c) 2007 Andreas Eberhard
+ * Licensed under GPL (http://www.opensource.org/licenses/gpl-license.php)
+ *
+ * Changelog:
+ *    09.03.2009 Version 1.2
+ *    - Update for jQuery 1.3.x, removed @ from selectors
+ *    11.09.2007 Version 1.1
+ *    - removed noConflict
+ *    - added png-support for input type=image
+ *    - 01.08.2007 CSS background-image support extension added by Scott Jehl, scott@filamentgroup.com, http://www.filamentgroup.com
+ *    31.05.2007 initial Version 1.0
+ * --------------------------------------------------------------------
+ * @example $(function(){$(document).pngFix();});
+ * @desc Fixes all PNG's in the document on document.ready
+ *
+ * jQuery(function(){jQuery(document).pngFix();});
+ * @desc Fixes all PNG's in the document on document.ready when using noConflict
+ *
+ * @example $(function(){$('div.examples').pngFix();});
+ * @desc Fixes all PNG's within div with class examples
+ *
+ * @example $(function(){$('div.examples').pngFix( { blankgif:'ext.gif' } );});
+ * @desc Fixes all PNG's within div with class examples, provides blank gif for input with png
+ * --------------------------------------------------------------------
+ */
+
+(function($) {
+
+jQuery.fn.pngFix = function(settings) {
+
+       // Settings
+       settings = jQuery.extend({
+               blankgif: 'blank.gif'
+       }, settings);
+
+       var ie55 = (navigator.appName == "Microsoft Internet Explorer" && parseInt(navigator.appVersion) == 4 && navigator.appVersion.indexOf("MSIE 5.5") != -1);
+       var ie6 = (navigator.appName == "Microsoft Internet Explorer" && parseInt(navigator.appVersion) == 4 && navigator.appVersion.indexOf("MSIE 6.0") != -1);
+
+       if (jQuery.browser.msie && (ie55 || ie6)) {
+
+               //fix images with png-source
+               jQuery(this).find("img[src$=.png]").each(function() {
+
+                       jQuery(this).attr('width',jQuery(this).width());
+                       jQuery(this).attr('height',jQuery(this).height());
+
+                       var prevStyle = '';
+                       var strNewHTML = '';
+                       var imgId = (jQuery(this).attr('id')) ? 'id="' + jQuery(this).attr('id') + '" ' : '';
+                       var imgClass = (jQuery(this).attr('class')) ? 'class="' + jQuery(this).attr('class') + '" ' : '';
+                       var imgTitle = (jQuery(this).attr('title')) ? 'title="' + jQuery(this).attr('title') + '" ' : '';
+                       var imgAlt = (jQuery(this).attr('alt')) ? 'alt="' + jQuery(this).attr('alt') + '" ' : '';
+                       var imgAlign = (jQuery(this).attr('align')) ? 'float:' + jQuery(this).attr('align') + ';' : '';
+                       var imgHand = (jQuery(this).parent().attr('href')) ? 'cursor:hand;' : '';
+                       if (this.style.border) {
+                               prevStyle += 'border:'+this.style.border+';';
+                               this.style.border = '';
+                       }
+                       if (this.style.padding) {
+                               prevStyle += 'padding:'+this.style.padding+';';
+                               this.style.padding = '';
+                       }
+                       if (this.style.margin) {
+                               prevStyle += 'margin:'+this.style.margin+';';
+                               this.style.margin = '';
+                       }
+                       var imgStyle = (this.style.cssText);
+
+                       strNewHTML += '<span '+imgId+imgClass+imgTitle+imgAlt;
+                       strNewHTML += 'style="position:relative;white-space:pre-line;display:inline-block;background:transparent;'+imgAlign+imgHand;
+                       strNewHTML += 'width:' + jQuery(this).width() + 'px;' + 'height:' + jQuery(this).height() + 'px;';
+                       strNewHTML += 'filter:progid:DXImageTransform.Microsoft.AlphaImageLoader' + '(src=\'' + jQuery(this).attr('src') + '\', sizingMethod=\'scale\');';
+                       strNewHTML += imgStyle+'"></span>';
+                       if (prevStyle != ''){
+                               strNewHTML = '<span style="position:relative;display:inline-block;'+prevStyle+imgHand+'width:' + jQuery(this).width() + 'px;' + 'height:' + jQuery(this).height() + 'px;'+'">' + strNewHTML + '</span>';
+                       }
+
+                       jQuery(this).hide();
+                       jQuery(this).after(strNewHTML);
+
+               });
+
+               // fix css background pngs
+               jQuery(this).find("*").each(function(){
+                       var bgIMG = jQuery(this).css('background-image');
+                       if(bgIMG.indexOf(".png")!=-1){
+                               var iebg = bgIMG.split('url("')[1].split('")')[0];
+                               jQuery(this).css('background-image', 'none');
+                               jQuery(this).get(0).runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + iebg + "',sizingMethod='scale')";
+                       }
+               });
+               
+               //fix input with png-source
+               jQuery(this).find("input[src$=.png]").each(function() {
+                       var bgIMG = jQuery(this).attr('src');
+                       jQuery(this).get(0).runtimeStyle.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader' + '(src=\'' + bgIMG + '\', sizingMethod=\'scale\');';
+               jQuery(this).attr('src', settings.blankgif)
+               });
+       
+       }
+       
+       return jQuery;
+
+};
+
+})(jQuery);
index 8b3f00f..cc5da1d 100644 (file)
-body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td { \r
-       margin:0;\r
-       padding:0;\r
-}\r
-table {\r
-       border-collapse:collapse;\r
-       border-spacing:0;\r
-}\r
-fieldset,img { \r
-       border:0;\r
-}\r
-address,caption,cite,code,dfn,em,strong,th,var {\r
-       font-style:normal;\r
-       font-weight:normal;\r
-}\r
-ol,ul {\r
-       list-style:none;\r
-}\r
-caption,th {\r
-       text-align:left;\r
-}\r
-h1,h2,h3,h4,h5,h6 {\r
-       font-size:100%;\r
-       font-weight:normal;\r
-}\r
-q:before,q:after {\r
-       content:'';\r
-}\r
-abbr,acronym { border:0;\r
-}\r
-html, body {\r
-       background-color: #fff;\r
-       font-family: Arial, Helvetica, sans-serif;\r
-       font-size: 12px;\r
-       line-height: 18px;\r
-       color: #52697E;\r
-}\r
-body {\r
-       text-align: center;\r
-       overflow: auto;\r
-}\r
-.wrapper {\r
-       width: 700px;\r
-       margin: 0 auto;\r
-       text-align: left;\r
-}\r
-h1 {\r
-       font-size: 21px;\r
-       height: 47px;\r
-       line-height: 47px;\r
-       text-transform: uppercase;\r
-}\r
-.navigationTabs {\r
-       height: 23px;\r
-       line-height: 23px;\r
-       border-bottom: 1px solid #ccc;\r
-}\r
-.navigationTabs li {\r
-       float: left;\r
-       height: 23px;\r
-       line-height: 23px;\r
-       padding-right: 3px;\r
-}\r
-.navigationTabs li a{\r
-       float: left;\r
-       dispaly: block;\r
-       height: 23px;\r
-       line-height: 23px;\r
-       padding: 0 10px;\r
-       overflow: hidden;\r
-       color: #52697E;\r
-       background-color: #eee;\r
-       position: relative;\r
-       text-decoration: none;\r
-}\r
-.navigationTabs li a:hover {\r
-       background-color: #f0f0f0;\r
-}\r
-.navigationTabs li a.active {\r
-       background-color: #fff;\r
-       border: 1px solid #ccc;\r
-       border-bottom: 0px solid;\r
-}\r
-.tabsContent {\r
-       border: 1px solid #ccc;\r
-       border-top: 0px solid;\r
-       width: 698px;\r
-       overflow: hidden;\r
-}\r
-.tab {\r
-       padding: 16px;\r
-       display: none;\r
-}\r
-.tab h2 {\r
-       font-weight: bold;\r
-       font-size: 16px;\r
-}\r
-.tab h3 {\r
-       font-weight: bold;\r
-       font-size: 14px;\r
-       margin-top: 20px;\r
-}\r
-.tab p {\r
-       margin-top: 16px;\r
-       clear: both;\r
-}\r
-.tab ul {\r
-       margin-top: 16px;\r
-       list-style: disc;\r
-}\r
-.tab li {\r
-       margin: 10px 0 0 35px;\r
-}\r
-.tab a {\r
-       color: #8FB0CF;\r
-}\r
-.tab strong {\r
-       font-weight: bold;\r
-}\r
-.tab pre {\r
-       font-size: 11px;\r
-       margin-top: 20px;\r
-       width: 668px;\r
-       overflow: auto;\r
-       clear: both;\r
-}\r
-.tab table {\r
-       width: 100%;\r
-}\r
-.tab table td {\r
-       padding: 6px 10px 6px 0;\r
-       vertical-align: top;\r
-}\r
-.tab dt {\r
-       margin-top: 16px;\r
-}\r
-\r
-#colorSelector {\r
-       position: relative;\r
-       width: 36px;\r
-       height: 36px;\r
-       background: url(../images/select.png);\r
-}\r
-#colorSelector div {\r
-       position: absolute;\r
-       top: 3px;\r
-       left: 3px;\r
-       width: 30px;\r
-       height: 30px;\r
-       background: url(../images/select.png) center;\r
-}\r
-#colorSelector2 {\r
-       position: absolute;\r
-       top: 0;\r
-       left: 0;\r
-       width: 36px;\r
-       height: 36px;\r
-       background: url(../images/select2.png);\r
-}\r
-#colorSelector2 div {\r
-       position: absolute;\r
-       top: 4px;\r
-       left: 4px;\r
-       width: 28px;\r
-       height: 28px;\r
-       background: url(../images/select2.png) center;\r
-}\r
-#colorpickerHolder2 {\r
-       top: 32px;\r
-       left: 0;\r
-       width: 356px;\r
-       height: 0;\r
-       overflow: hidden;\r
-       position: absolute;\r
-}\r
-#colorpickerHolder2 .colorpicker {\r
-       background-image: url(../images/custom_background.png);\r
-       position: absolute;\r
-       bottom: 0;\r
-       left: 0;\r
-}\r
-#colorpickerHolder2 .colorpicker_hue div {\r
-       background-image: url(../images/custom_indic.gif);\r
-}\r
-#colorpickerHolder2 .colorpicker_hex {\r
-       background-image: url(../images/custom_hex.png);\r
-}\r
-#colorpickerHolder2 .colorpicker_rgb_r {\r
-       background-image: url(../images/custom_rgb_r.png);\r
-}\r
-#colorpickerHolder2 .colorpicker_rgb_g {\r
-       background-image: url(../images/custom_rgb_g.png);\r
-}\r
-#colorpickerHolder2 .colorpicker_rgb_b {\r
-       background-image: url(../images/custom_rgb_b.png);\r
-}\r
-#colorpickerHolder2 .colorpicker_hsb_s {\r
-       background-image: url(../images/custom_hsb_s.png);\r
-       display: none;\r
-}\r
-#colorpickerHolder2 .colorpicker_hsb_h {\r
-       background-image: url(../images/custom_hsb_h.png);\r
-       display: none;\r
-}\r
-#colorpickerHolder2 .colorpicker_hsb_b {\r
-       background-image: url(../images/custom_hsb_b.png);\r
-       display: none;\r
-}\r
-#colorpickerHolder2 .colorpicker_submit {\r
-       background-image: url(../images/custom_submit.png);\r
-}\r
-#colorpickerHolder2 .colorpicker input {\r
-       color: #778398;\r
-}\r
-#customWidget {\r
-       position: relative;\r
-       height: 36px;\r
-}\r
+body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td { 
+       margin:0;
+       padding:0;
+}
+table {
+       border-collapse:collapse;
+       border-spacing:0;
+}
+fieldset,img { 
+       border:0;
+}
+address,caption,cite,code,dfn,em,strong,th,var {
+       font-style:normal;
+       font-weight:normal;
+}
+ol,ul {
+       list-style:none;
+}
+caption,th {
+       text-align:left;
+}
+h1,h2,h3,h4,h5,h6 {
+       font-size:100%;
+       font-weight:normal;
+}
+q:before,q:after {
+       content:'';
+}
+abbr,acronym { border:0;
+}
+html, body {
+       background-color: #fff;
+       font-family: Arial, Helvetica, sans-serif;
+       font-size: 12px;
+       line-height: 18px;
+       color: #52697E;
+}
+body {
+       text-align: center;
+       overflow: auto;
+}
+.wrapper {
+       width: 700px;
+       margin: 0 auto;
+       text-align: left;
+}
+h1 {
+       font-size: 21px;
+       height: 47px;
+       line-height: 47px;
+       text-transform: uppercase;
+}
+.navigationTabs {
+       height: 23px;
+       line-height: 23px;
+       border-bottom: 1px solid #ccc;
+}
+.navigationTabs li {
+       float: left;
+       height: 23px;
+       line-height: 23px;
+       padding-right: 3px;
+}
+.navigationTabs li a{
+       float: left;
+       dispaly: block;
+       height: 23px;
+       line-height: 23px;
+       padding: 0 10px;
+       overflow: hidden;
+       color: #52697E;
+       background-color: #eee;
+       position: relative;
+       text-decoration: none;
+}
+.navigationTabs li a:hover {
+       background-color: #f0f0f0;
+}
+.navigationTabs li a.active {
+       background-color: #fff;
+       border: 1px solid #ccc;
+       border-bottom: 0px solid;
+}
+.tabsContent {
+       border: 1px solid #ccc;
+       border-top: 0px solid;
+       width: 698px;
+       overflow: hidden;
+}
+.tab {
+       padding: 16px;
+       display: none;
+}
+.tab h2 {
+       font-weight: bold;
+       font-size: 16px;
+}
+.tab h3 {
+       font-weight: bold;
+       font-size: 14px;
+       margin-top: 20px;
+}
+.tab p {
+       margin-top: 16px;
+       clear: both;
+}
+.tab ul {
+       margin-top: 16px;
+       list-style: disc;
+}
+.tab li {
+       margin: 10px 0 0 35px;
+}
+.tab a {
+       color: #8FB0CF;
+}
+.tab strong {
+       font-weight: bold;
+}
+.tab pre {
+       font-size: 11px;
+       margin-top: 20px;
+       width: 668px;
+       overflow: auto;
+       clear: both;
+}
+.tab table {
+       width: 100%;
+}
+.tab table td {
+       padding: 6px 10px 6px 0;
+       vertical-align: top;
+}
+.tab dt {
+       margin-top: 16px;
+}
+
+#colorSelector {
+       position: relative;
+       width: 36px;
+       height: 36px;
+       background: url(../images/select.png);
+}
+#colorSelector div {
+       position: absolute;
+       top: 3px;
+       left: 3px;
+       width: 30px;
+       height: 30px;
+       background: url(../images/select.png) center;
+}
+#colorSelector2 {
+       position: absolute;
+       top: 0;
+       left: 0;
+       width: 36px;
+       height: 36px;
+       background: url(../images/select2.png);
+}
+#colorSelector2 div {
+       position: absolute;
+       top: 4px;
+       left: 4px;
+       width: 28px;
+       height: 28px;
+       background: url(../images/select2.png) center;
+}
+#colorpickerHolder2 {
+       top: 32px;
+       left: 0;
+       width: 356px;
+       height: 0;
+       overflow: hidden;
+       position: absolute;
+}
+#colorpickerHolder2 .colorpicker {
+       background-image: url(../images/custom_background.png);
+       position: absolute;
+       bottom: 0;
+       left: 0;
+}
+#colorpickerHolder2 .colorpicker_hue div {
+       background-image: url(../images/custom_indic.gif);
+}
+#colorpickerHolder2 .colorpicker_hex {
+       background-image: url(../images/custom_hex.png);
+}
+#colorpickerHolder2 .colorpicker_rgb_r {
+       background-image: url(../images/custom_rgb_r.png);
+}
+#colorpickerHolder2 .colorpicker_rgb_g {
+       background-image: url(../images/custom_rgb_g.png);
+}
+#colorpickerHolder2 .colorpicker_rgb_b {
+       background-image: url(../images/custom_rgb_b.png);
+}
+#colorpickerHolder2 .colorpicker_hsb_s {
+       background-image: url(../images/custom_hsb_s.png);
+       display: none;
+}
+#colorpickerHolder2 .colorpicker_hsb_h {
+       background-image: url(../images/custom_hsb_h.png);
+       display: none;
+}
+#colorpickerHolder2 .colorpicker_hsb_b {
+       background-image: url(../images/custom_hsb_b.png);
+       display: none;
+}
+#colorpickerHolder2 .colorpicker_submit {
+       background-image: url(../images/custom_submit.png);
+}
+#colorpickerHolder2 .colorpicker input {
+       color: #778398;
+}
+#customWidget {
+       position: relative;
+       height: 36px;
+}
index e1ad578..f8da8af 100644 (file)
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\r
-<head>\r
-       <link rel="stylesheet" href="css/colorpicker.css" type="text/css" />\r
-    <link rel="stylesheet" media="screen" type="text/css" href="css/layout.css" />\r
-    <title>ColorPicker - jQuery plugin</title>\r
-       <script type="text/javascript" src="js/jquery.js"></script>\r
-       <script type="text/javascript" src="js/colorpicker.js"></script>\r
-    <script type="text/javascript" src="js/eye.js"></script>\r
-    <script type="text/javascript" src="js/utils.js"></script>\r
-    <script type="text/javascript" src="js/layout.js?ver=1.0.2"></script>\r
-</head>\r
-<body>\r
-    <div class="wrapper">\r
-        <h1>Color Picker - jQuery plugin</h1>\r
-        <ul class="navigationTabs">\r
-            <li><a href="#about" rel="about">About</a></li>\r
-            <li><a href="#download" rel="download">Download</a></li>\r
-            <li><a href="#implement" rel="implement">Implement</a></li>\r
-        </ul>\r
-        <div class="tabsContent">\r
-            <div class="tab">\r
-                <h2>About</h2>\r
-                <p>A simple component to select color in the same way you select color in Adobe Photoshop</p>\r
-                               <h3>Last update</h3>\r
-                               <p>23.05.2009 - Check Download tab</p>\r
-                <h3>Features</h3>\r
-                <ul>\r
-                    <li>Flat mode - as element in page</li>\r
-                    <li>Powerful controls for color selection</li>\r
-                                       <li>Easy to customize the look by changing some images</li>\r
-                                       <li>Fits into the viewport</li>\r
-                </ul>\r
-                               <h3>License</h3>\r
-                               <p>Dual licensed under the MIT and GPL licenses.</p>\r
-                <h3>Examples</h3>\r
-                <p>Flat mode.</p>\r
-                <p id="colorpickerHolder">\r
-                </p>\r
-                <pre>\r
-$('#colorpickerHolder').ColorPicker({flat: true});\r
-                </pre>\r
-                <p>Custom skin and using flat mode to display the color picker in a custom widget.</p>\r
-                               <div id="customWidget">\r
-                                       <div id="colorSelector2"><div style="background-color: #00ff00"></div></div>\r
-                       <div id="colorpickerHolder2">\r
-                       </div>\r
-                               </div>\r
-\r
-                               <p>Attached to an text field and using callback functions to update the color with field's value and set the value back in the field by submiting the color.</p>\r
-                               <p><input type="text" maxlength="6" size="6" id="colorpickerField1" value="00ff00" /></p>\r
-                               <p><input type="text" maxlength="6" size="6" id="colorpickerField3" value="0000ff" /></p>\r
-                               <p><input type="text" maxlength="6" size="6" id="colorpickerField2" value="ff0000" /></p>\r
-                               <pre>$('#colorpickerField1, #colorpickerField2, #colorpickerField3').ColorPicker({\r
-       onSubmit: function(hsb, hex, rgb, el) {\r
-               $(el).val(hex);\r
-               $(el).ColorPickerHide();\r
-       },\r
-       onBeforeShow: function () {\r
-               $(this).ColorPickerSetColor(this.value);\r
-       }\r
-})\r
-.bind('keyup', function(){\r
-       $(this).ColorPickerSetColor(this.value);\r
-});\r
-</pre>\r
-                               <p>Attached to DOMElement and using callbacks to live preview the color and adding animation.</p>\r
-                               <p>\r
-                                       <div id="colorSelector"><div style="background-color: #0000ff"></div></div>\r
-                               </p>\r
-                               <pre>\r
-$('#colorSelector').ColorPicker({\r
-       color: '#0000ff',\r
-       onShow: function (colpkr) {\r
-               $(colpkr).fadeIn(500);\r
-               return false;\r
-       },\r
-       onHide: function (colpkr) {\r
-               $(colpkr).fadeOut(500);\r
-               return false;\r
-       },\r
-       onChange: function (hsb, hex, rgb) {\r
-               $('#colorSelector div').css('backgroundColor', '#' + hex);\r
-       }\r
-});\r
-</pre>\r
-            </div>\r
-            <div class="tab">\r
-                <h2>Download</h2>\r
-                <p><a href="colorpicker.zip">colorpicker.zip (73 kb)</a>: jQuery, Javscript files, CSS files, images, examples and instructions.</p>\r
-                <h3>Changelog</h3>\r
-                <dl>\r
-                                       <dt>23.05.2009</dt>\r
-                                       <dd>Added: close on color selection example</dd>\r
-                                       <dd>Added: restore original color option</dd>\r
-                                       <dd>Changed: color update on key up event</dd>\r
-                                       <dd>Fixed: colorpicker hide and show methods</dd>\r
-                                       <dd>Fixed: reference to options. Multiple fields with colorpickers is possible now.</dd>\r
-                                       <dd>Fixed: RGB to HSB convertion</dd>\r
-                                       <dt>22.08.2008</dt>\r
-                                       <dd>Fixed bug: where some events were not canceled right on Safari</dd>\r
-                                       <dd>Fixed bug: where teh view port was not detected right on Safari</dd>\r
-                                       <dt>16-07-2008</dt>\r
-                                       <dd>Fixed bug where the letter 'F' could not be typed in the Hex field</dd>\r
-                                       <dd>Fixed bug where the changes on Hex field where not parsed</dd>\r
-                                       <dd>Added new option 'livePreview'</dd>\r
-                                       <dt>08-07-2008</dt>\r
-                                       <dd>Fixed typo in the code, both JavaScript and CSS</dd>\r
-                                       <dd>Changed the cursor for some elements</dd>\r
-                                       <dd>Added new demo explaining how to implement custom skin</dd>\r
-                                       <dt>07.07.2008</dt>\r
-                                       <dd>The first release.</dd>\r
-                </dl>\r
-            </div>\r
-            <div class="tab">\r
-                <h2>Implement</h2>\r
-                <p>Attach the Javascript and CSS files to your document. Edit CSS file and fix the paths to  images and change colors to fit your site theme.</p>\r
-                <pre>\r
-&lt;link rel="stylesheet" media="screen" type="text/css" href="css/colorpicker.css" /&gt;\r
-&lt;script type="text/javascript" src="js/colorpicker.js"&gt;&lt;/script&gt;\r
-                </pre>\r
-                <h3>Invocation code</h3>\r
-                <p>All you have to do is to select the elements in a jQuery way and call the plugin.</p>\r
-                <pre>\r
- $('input').ColorPicker(options);\r
-                </pre>\r
-                <h3>Options</h3>\r
-                <p>A hash of parameters. All parameters are optional.</p>\r
-                <table>\r
-                       <tr>\r
-                               <td><strong>eventName</strong></td>\r
-                               <td>string</td>\r
-                               <td>The desired event to trigger the colorpicker. Default: 'click'</td>\r
-                       </tr>\r
-                       <tr>\r
-                               <td><strong>color</strong></td>\r
-                               <td>string or hash</td>\r
-                               <td>The default color. String for hex color or hash for RGB and HSB ({r:255, r:0, b:0}) . Default: 'ff0000'</td>\r
-                       </tr>\r
-                       <tr>\r
-                               <td><strong>flat</strong></td>\r
-                               <td>boolean</td>\r
-                               <td>Whatever if the color picker is appended to the element or triggered by an event. Default false</td>\r
-                       </tr>\r
-                       <tr>\r
-                               <td><strong>livePreview</strong></td>\r
-                               <td>boolean</td>\r
-                               <td>Whatever if the color values are filled in the fields while changing values on selector or a field. If false it may improve speed. Default true</td>\r
-                       </tr>\r
-                       <tr>\r
-                               <td><strong>onShow</strong></td>\r
-                               <td>function</td>\r
-                               <td>Callback function triggered when the color picker is shown</td>\r
-                       </tr>\r
-                       <tr>\r
-                               <td><strong>onBeforeShow</strong></td>\r
-                               <td>function</td>\r
-                               <td>Callback function triggered before the color picker is shown</td>\r
-                       </tr>\r
-                       <tr>\r
-                               <td><strong>onHide</strong></td>\r
-                               <td>function</td>\r
-                               <td>Callback function triggered when the color picker is hidden</td>\r
-                       </tr>\r
-                       <tr>\r
-                               <td><strong>onChange</strong></td>\r
-                               <td>function</td>\r
-                               <td>Callback function triggered when the color is changed</td>\r
-                       </tr>\r
-                       <tr>\r
-                               <td><strong>onSubmit</strong></td>\r
-                               <td>function</td>\r
-                               <td>Callback function triggered when the color it is chosen</td>\r
-                       </tr>\r
-                </table>\r
-                <h3>Set color</h3>\r
-                <p>If you want to set a new color.</p>\r
-                <pre>$('input').ColorPickerSetColor(color);</pre>\r
-                               <p>The 'color' argument is the same format as the option color, string for hex color or hash for RGB and HSB ({r:255, r:0, b:0}).</p>\r
-            </div>\r
-        </div>\r
-    </div>\r
-</body>\r
-</html>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+       <link rel="stylesheet" href="css/colorpicker.css" type="text/css" />
+    <link rel="stylesheet" media="screen" type="text/css" href="css/layout.css" />
+    <title>ColorPicker - jQuery plugin</title>
+       <script type="text/javascript" src="js/jquery.js"></script>
+       <script type="text/javascript" src="js/colorpicker.js"></script>
+    <script type="text/javascript" src="js/eye.js"></script>
+    <script type="text/javascript" src="js/utils.js"></script>
+    <script type="text/javascript" src="js/layout.js?ver=1.0.2"></script>
+</head>
+<body>
+    <div class="wrapper">
+        <h1>Color Picker - jQuery plugin</h1>
+        <ul class="navigationTabs">
+            <li><a href="#about" rel="about">About</a></li>
+            <li><a href="#download" rel="download">Download</a></li>
+            <li><a href="#implement" rel="implement">Implement</a></li>
+        </ul>
+        <div class="tabsContent">
+            <div class="tab">
+                <h2>About</h2>
+                <p>A simple component to select color in the same way you select color in Adobe Photoshop</p>
+                               <h3>Last update</h3>
+                               <p>23.05.2009 - Check Download tab</p>
+                <h3>Features</h3>
+                <ul>
+                    <li>Flat mode - as element in page</li>
+                    <li>Powerful controls for color selection</li>
+                                       <li>Easy to customize the look by changing some images</li>
+                                       <li>Fits into the viewport</li>
+                </ul>
+                               <h3>License</h3>
+                               <p>Dual licensed under the MIT and GPL licenses.</p>
+                <h3>Examples</h3>
+                <p>Flat mode.</p>
+                <p id="colorpickerHolder">
+                </p>
+                <pre>
+$('#colorpickerHolder').ColorPicker({flat: true});
+                </pre>
+                <p>Custom skin and using flat mode to display the color picker in a custom widget.</p>
+                               <div id="customWidget">
+                                       <div id="colorSelector2"><div style="background-color: #00ff00"></div></div>
+                       <div id="colorpickerHolder2">
+                       </div>
+                               </div>
+
+                               <p>Attached to an text field and using callback functions to update the color with field's value and set the value back in the field by submiting the color.</p>
+                               <p><input type="text" maxlength="6" size="6" id="colorpickerField1" value="00ff00" /></p>
+                               <p><input type="text" maxlength="6" size="6" id="colorpickerField3" value="0000ff" /></p>
+                               <p><input type="text" maxlength="6" size="6" id="colorpickerField2" value="ff0000" /></p>
+                               <pre>$('#colorpickerField1, #colorpickerField2, #colorpickerField3').ColorPicker({
+       onSubmit: function(hsb, hex, rgb, el) {
+               $(el).val(hex);
+               $(el).ColorPickerHide();
+       },
+       onBeforeShow: function () {
+               $(this).ColorPickerSetColor(this.value);
+       }
+})
+.bind('keyup', function(){
+       $(this).ColorPickerSetColor(this.value);
+});
+</pre>
+                               <p>Attached to DOMElement and using callbacks to live preview the color and adding animation.</p>
+                               <p>
+                                       <div id="colorSelector"><div style="background-color: #0000ff"></div></div>
+                               </p>
+                               <pre>
+$('#colorSelector').ColorPicker({
+       color: '#0000ff',
+       onShow: function (colpkr) {
+               $(colpkr).fadeIn(500);
+               return false;
+       },
+       onHide: function (colpkr) {
+               $(colpkr).fadeOut(500);
+               return false;
+       },
+       onChange: function (hsb, hex, rgb) {
+               $('#colorSelector div').css('backgroundColor', '#' + hex);
+       }
+});
+</pre>
+            </div>
+            <div class="tab">
+                <h2>Download</h2>
+                <p><a href="colorpicker.zip">colorpicker.zip (73 kb)</a>: jQuery, Javscript files, CSS files, images, examples and instructions.</p>
+                <h3>Changelog</h3>
+                <dl>
+                                       <dt>23.05.2009</dt>
+                                       <dd>Added: close on color selection example</dd>
+                                       <dd>Added: restore original color option</dd>
+                                       <dd>Changed: color update on key up event</dd>
+                                       <dd>Fixed: colorpicker hide and show methods</dd>
+                                       <dd>Fixed: reference to options. Multiple fields with colorpickers is possible now.</dd>
+                                       <dd>Fixed: RGB to HSB convertion</dd>
+                                       <dt>22.08.2008</dt>
+                                       <dd>Fixed bug: where some events were not canceled right on Safari</dd>
+                                       <dd>Fixed bug: where teh view port was not detected right on Safari</dd>
+                                       <dt>16-07-2008</dt>
+                                       <dd>Fixed bug where the letter 'F' could not be typed in the Hex field</dd>
+                                       <dd>Fixed bug where the changes on Hex field where not parsed</dd>
+                                       <dd>Added new option 'livePreview'</dd>
+                                       <dt>08-07-2008</dt>
+                                       <dd>Fixed typo in the code, both JavaScript and CSS</dd>
+                                       <dd>Changed the cursor for some elements</dd>
+                                       <dd>Added new demo explaining how to implement custom skin</dd>
+                                       <dt>07.07.2008</dt>
+                                       <dd>The first release.</dd>
+                </dl>
+            </div>
+            <div class="tab">
+                <h2>Implement</h2>
+                <p>Attach the Javascript and CSS files to your document. Edit CSS file and fix the paths to  images and change colors to fit your site theme.</p>
+                <pre>
+&lt;link rel="stylesheet" media="screen" type="text/css" href="css/colorpicker.css" /&gt;
+&lt;script type="text/javascript" src="js/colorpicker.js"&gt;&lt;/script&gt;
+                </pre>
+                <h3>Invocation code</h3>
+                <p>All you have to do is to select the elements in a jQuery way and call the plugin.</p>
+                <pre>
+ $('input').ColorPicker(options);
+                </pre>
+                <h3>Options</h3>
+                <p>A hash of parameters. All parameters are optional.</p>
+                <table>
+                       <tr>
+                               <td><strong>eventName</strong></td>
+                               <td>string</td>
+                               <td>The desired event to trigger the colorpicker. Default: 'click'</td>
+                       </tr>
+                       <tr>
+                               <td><strong>color</strong></td>
+                               <td>string or hash</td>
+                               <td>The default color. String for hex color or hash for RGB and HSB ({r:255, r:0, b:0}) . Default: 'ff0000'</td>
+                       </tr>
+                       <tr>
+                               <td><strong>flat</strong></td>
+                               <td>boolean</td>
+                               <td>Whatever if the color picker is appended to the element or triggered by an event. Default false</td>
+                       </tr>
+                       <tr>
+                               <td><strong>livePreview</strong></td>
+                               <td>boolean</td>
+                               <td>Whatever if the color values are filled in the fields while changing values on selector or a field. If false it may improve speed. Default true</td>
+                       </tr>
+                       <tr>
+                               <td><strong>onShow</strong></td>
+                               <td>function</td>
+                               <td>Callback function triggered when the color picker is shown</td>
+                       </tr>
+                       <tr>
+                               <td><strong>onBeforeShow</strong></td>
+                               <td>function</td>
+                               <td>Callback function triggered before the color picker is shown</td>
+                       </tr>
+                       <tr>
+                               <td><strong>onHide</strong></td>
+                               <td>function</td>
+                               <td>Callback function triggered when the color picker is hidden</td>
+                       </tr>
+                       <tr>
+                               <td><strong>onChange</strong></td>
+                               <td>function</td>
+                               <td>Callback function triggered when the color is changed</td>
+                       </tr>
+                       <tr>
+                               <td><strong>onSubmit</strong></td>
+                               <td>function</td>
+                               <td>Callback function triggered when the color it is chosen</td>
+                       </tr>
+                </table>
+                <h3>Set color</h3>
+                <p>If you want to set a new color.</p>
+                <pre>$('input').ColorPickerSetColor(color);</pre>
+                               <p>The 'color' argument is the same format as the option color, string for hex color or hash for RGB and HSB ({r:255, r:0, b:0}).</p>
+            </div>
+        </div>
+    </div>
+</body>
+</html>
index 10a2b22..45f56ce 100644 (file)
-/**\r
- *\r
- * Color picker\r
- * Author: Stefan Petre www.eyecon.ro\r
- * \r
- * Dual licensed under the MIT and GPL licenses\r
- * \r
- */\r
-(function ($) {\r
-       var ColorPicker = function () {\r
-               var\r
-                       ids = {},\r
-                       inAction,\r
-                       charMin = 65,\r
-                       visible,\r
-                       tpl = '<div class="colorpicker"><div class="colorpicker_color"><div><div></div></div></div><div class="colorpicker_hue"><div></div></div><div class="colorpicker_new_color"></div><div class="colorpicker_current_color"></div><div class="colorpicker_hex"><input type="text" maxlength="6" size="6" /></div><div class="colorpicker_rgb_r colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_g colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_h colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_s colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_submit"></div></div>',\r
-                       defaults = {\r
-                               eventName: 'click',\r
-                               onShow: function () {},\r
-                               onBeforeShow: function(){},\r
-                               onHide: function () {},\r
-                               onChange: function () {},\r
-                               onSubmit: function () {},\r
-                               color: 'ff0000',\r
-                               livePreview: true,\r
-                               flat: false\r
-                       },\r
-                       fillRGBFields = function  (hsb, cal) {\r
-                               var rgb = HSBToRGB(hsb);\r
-                               $(cal).data('colorpicker').fields\r
-                                       .eq(1).val(rgb.r).end()\r
-                                       .eq(2).val(rgb.g).end()\r
-                                       .eq(3).val(rgb.b).end();\r
-                       },\r
-                       fillHSBFields = function  (hsb, cal) {\r
-                               $(cal).data('colorpicker').fields\r
-                                       .eq(4).val(hsb.h).end()\r
-                                       .eq(5).val(hsb.s).end()\r
-                                       .eq(6).val(hsb.b).end();\r
-                       },\r
-                       fillHexFields = function (hsb, cal) {\r
-                               $(cal).data('colorpicker').fields\r
-                                       .eq(0).val(HSBToHex(hsb)).end();\r
-                       },\r
-                       setSelector = function (hsb, cal) {\r
-                               $(cal).data('colorpicker').selector.css('backgroundColor', '#' + HSBToHex({h: hsb.h, s: 100, b: 100}));\r
-                               $(cal).data('colorpicker').selectorIndic.css({\r
-                                       left: parseInt(150 * hsb.s/100, 10),\r
-                                       top: parseInt(150 * (100-hsb.b)/100, 10)\r
-                               });\r
-                       },\r
-                       setHue = function (hsb, cal) {\r
-                               $(cal).data('colorpicker').hue.css('top', parseInt(150 - 150 * hsb.h/360, 10));\r
-                       },\r
-                       setCurrentColor = function (hsb, cal) {\r
-                               $(cal).data('colorpicker').currentColor.css('backgroundColor', '#' + HSBToHex(hsb));\r
-                       },\r
-                       setNewColor = function (hsb, cal) {\r
-                               $(cal).data('colorpicker').newColor.css('backgroundColor', '#' + HSBToHex(hsb));\r
-                       },\r
-                       keyDown = function (ev) {\r
-                               var pressedKey = ev.charCode || ev.keyCode || -1;\r
-                               if ((pressedKey > charMin && pressedKey <= 90) || pressedKey == 32) {\r
-                                       return false;\r
-                               }\r
-                               var cal = $(this).parent().parent();\r
-                               if (cal.data('colorpicker').livePreview === true) {\r
-                                       change.apply(this);\r
-                               }\r
-                       },\r
-                       change = function (ev) {\r
-                               var cal = $(this).parent().parent(), col;\r
-                               if (this.parentNode.className.indexOf('_hex') > 0) {\r
-                                       cal.data('colorpicker').color = col = HexToHSB(fixHex(this.value));\r
-                               } else if (this.parentNode.className.indexOf('_hsb') > 0) {\r
-                                       cal.data('colorpicker').color = col = fixHSB({\r
-                                               h: parseInt(cal.data('colorpicker').fields.eq(4).val(), 10),\r
-                                               s: parseInt(cal.data('colorpicker').fields.eq(5).val(), 10),\r
-                                               b: parseInt(cal.data('colorpicker').fields.eq(6).val(), 10)\r
-                                       });\r
-                               } else {\r
-                                       cal.data('colorpicker').color = col = RGBToHSB(fixRGB({\r
-                                               r: parseInt(cal.data('colorpicker').fields.eq(1).val(), 10),\r
-                                               g: parseInt(cal.data('colorpicker').fields.eq(2).val(), 10),\r
-                                               b: parseInt(cal.data('colorpicker').fields.eq(3).val(), 10)\r
-                                       }));\r
-                               }\r
-                               if (ev) {\r
-                                       fillRGBFields(col, cal.get(0));\r
-                                       fillHexFields(col, cal.get(0));\r
-                                       fillHSBFields(col, cal.get(0));\r
-                               }\r
-                               setSelector(col, cal.get(0));\r
-                               setHue(col, cal.get(0));\r
-                               setNewColor(col, cal.get(0));\r
-                               cal.data('colorpicker').onChange.apply(cal, [col, HSBToHex(col), HSBToRGB(col)]);\r
-                       },\r
-                       blur = function (ev) {\r
-                               var cal = $(this).parent().parent();\r
-                               cal.data('colorpicker').fields.parent().removeClass('colorpicker_focus');\r
-                       },\r
-                       focus = function () {\r
-                               charMin = this.parentNode.className.indexOf('_hex') > 0 ? 70 : 65;\r
-                               $(this).parent().parent().data('colorpicker').fields.parent().removeClass('colorpicker_focus');\r
-                               $(this).parent().addClass('colorpicker_focus');\r
-                       },\r
-                       downIncrement = function (ev) {\r
-                               var field = $(this).parent().find('input').focus();\r
-                               var current = {\r
-                                       el: $(this).parent().addClass('colorpicker_slider'),\r
-                                       max: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255),\r
-                                       y: ev.pageY,\r
-                                       field: field,\r
-                                       val: parseInt(field.val(), 10),\r
-                                       preview: $(this).parent().parent().data('colorpicker').livePreview                                      \r
-                               };\r
-                               $(document).bind('mouseup', current, upIncrement);\r
-                               $(document).bind('mousemove', current, moveIncrement);\r
-                       },\r
-                       moveIncrement = function (ev) {\r
-                               ev.data.field.val(Math.max(0, Math.min(ev.data.max, parseInt(ev.data.val + ev.pageY - ev.data.y, 10))));\r
-                               if (ev.data.preview) {\r
-                                       change.apply(ev.data.field.get(0), [true]);\r
-                               }\r
-                               return false;\r
-                       },\r
-                       upIncrement = function (ev) {\r
-                               change.apply(ev.data.field.get(0), [true]);\r
-                               ev.data.el.removeClass('colorpicker_slider').find('input').focus();\r
-                               $(document).unbind('mouseup', upIncrement);\r
-                               $(document).unbind('mousemove', moveIncrement);\r
-                               return false;\r
-                       },\r
-                       downHue = function (ev) {\r
-                               var current = {\r
-                                       cal: $(this).parent(),\r
-                                       y: $(this).offset().top\r
-                               };\r
-                               current.preview = current.cal.data('colorpicker').livePreview;\r
-                               $(document).bind('mouseup', current, upHue);\r
-                               $(document).bind('mousemove', current, moveHue);\r
-                       },\r
-                       moveHue = function (ev) {\r
-                               change.apply(\r
-                                       ev.data.cal.data('colorpicker')\r
-                                               .fields\r
-                                               .eq(4)\r
-                                               .val(parseInt(360*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.y))))/150, 10))\r
-                                               .get(0),\r
-                                       [ev.data.preview]\r
-                               );\r
-                               return false;\r
-                       },\r
-                       upHue = function (ev) {\r
-                               fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));\r
-                               fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));\r
-                               $(document).unbind('mouseup', upHue);\r
-                               $(document).unbind('mousemove', moveHue);\r
-                               return false;\r
-                       },\r
-                       downSelector = function (ev) {\r
-                               var current = {\r
-                                       cal: $(this).parent(),\r
-                                       pos: $(this).offset()\r
-                               };\r
-                               current.preview = current.cal.data('colorpicker').livePreview;\r
-                               $(document).bind('mouseup', current, upSelector);\r
-                               $(document).bind('mousemove', current, moveSelector);\r
-                       },\r
-                       moveSelector = function (ev) {\r
-                               change.apply(\r
-                                       ev.data.cal.data('colorpicker')\r
-                                               .fields\r
-                                               .eq(6)\r
-                                               .val(parseInt(100*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.pos.top))))/150, 10))\r
-                                               .end()\r
-                                               .eq(5)\r
-                                               .val(parseInt(100*(Math.max(0,Math.min(150,(ev.pageX - ev.data.pos.left))))/150, 10))\r
-                                               .get(0),\r
-                                       [ev.data.preview]\r
-                               );\r
-                               return false;\r
-                       },\r
-                       upSelector = function (ev) {\r
-                               fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));\r
-                               fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));\r
-                               $(document).unbind('mouseup', upSelector);\r
-                               $(document).unbind('mousemove', moveSelector);\r
-                               return false;\r
-                       },\r
-                       enterSubmit = function (ev) {\r
-                               $(this).addClass('colorpicker_focus');\r
-                       },\r
-                       leaveSubmit = function (ev) {\r
-                               $(this).removeClass('colorpicker_focus');\r
-                       },\r
-                       clickSubmit = function (ev) {\r
-                               var cal = $(this).parent();\r
-                               var col = cal.data('colorpicker').color;\r
-                               cal.data('colorpicker').origColor = col;\r
-                               setCurrentColor(col, cal.get(0));\r
-                               cal.data('colorpicker').onSubmit(col, HSBToHex(col), HSBToRGB(col), cal.data('colorpicker').el);\r
-                       },\r
-                       show = function (ev) {\r
-                               var cal = $('#' + $(this).data('colorpickerId'));\r
-                               cal.data('colorpicker').onBeforeShow.apply(this, [cal.get(0)]);\r
-                               var pos = $(this).offset();\r
-                               var viewPort = getViewport();\r
-                               var top = pos.top + this.offsetHeight;\r
-                               var left = pos.left;\r
-                               if (top + 176 > viewPort.t + viewPort.h) {\r
-                                       top -= this.offsetHeight + 176;\r
-                               }\r
-                               if (left + 356 > viewPort.l + viewPort.w) {\r
-                                       left -= 356;\r
-                               }\r
-                               cal.css({left: left + 'px', top: top + 'px'});\r
-                               if (cal.data('colorpicker').onShow.apply(this, [cal.get(0)]) != false) {\r
-                                       cal.show();\r
-                               }\r
-                               $(document).bind('mousedown', {cal: cal}, hide);\r
-                               return false;\r
-                       },\r
-                       hide = function (ev) {\r
-                               if (!isChildOf(ev.data.cal.get(0), ev.target, ev.data.cal.get(0))) {\r
-                                       if (ev.data.cal.data('colorpicker').onHide.apply(this, [ev.data.cal.get(0)]) != false) {\r
-                                               ev.data.cal.hide();\r
-                                       }\r
-                                       $(document).unbind('mousedown', hide);\r
-                               }\r
-                       },\r
-                       isChildOf = function(parentEl, el, container) {\r
-                               if (parentEl == el) {\r
-                                       return true;\r
-                               }\r
-                               if (parentEl.contains) {\r
-                                       return parentEl.contains(el);\r
-                               }\r
-                               if ( parentEl.compareDocumentPosition ) {\r
-                                       return !!(parentEl.compareDocumentPosition(el) & 16);\r
-                               }\r
-                               var prEl = el.parentNode;\r
-                               while(prEl && prEl != container) {\r
-                                       if (prEl == parentEl)\r
-                                               return true;\r
-                                       prEl = prEl.parentNode;\r
-                               }\r
-                               return false;\r
-                       },\r
-                       getViewport = function () {\r
-                               var m = document.compatMode == 'CSS1Compat';\r
-                               return {\r
-                                       l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft),\r
-                                       t : window.pageYOffset || (m ? document.documentElement.scrollTop : document.body.scrollTop),\r
-                                       w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth),\r
-                                       h : window.innerHeight || (m ? document.documentElement.clientHeight : document.body.clientHeight)\r
-                               };\r
-                       },\r
-                       fixHSB = function (hsb) {\r
-                               return {\r
-                                       h: Math.min(360, Math.max(0, hsb.h)),\r
-                                       s: Math.min(100, Math.max(0, hsb.s)),\r
-                                       b: Math.min(100, Math.max(0, hsb.b))\r
-                               };\r
-                       }, \r
-                       fixRGB = function (rgb) {\r
-                               return {\r
-                                       r: Math.min(255, Math.max(0, rgb.r)),\r
-                                       g: Math.min(255, Math.max(0, rgb.g)),\r
-                                       b: Math.min(255, Math.max(0, rgb.b))\r
-                               };\r
-                       },\r
-                       fixHex = function (hex) {\r
-                               var len = 6 - hex.length;\r
-                               if (len > 0) {\r
-                                       var o = [];\r
-                                       for (var i=0; i<len; i++) {\r
-                                               o.push('0');\r
-                                       }\r
-                                       o.push(hex);\r
-                                       hex = o.join('');\r
-                               }\r
-                               return hex;\r
-                       }, \r
-                       HexToRGB = function (hex) {\r
-                               var hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);\r
-                               return {r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF)};\r
-                       },\r
-                       HexToHSB = function (hex) {\r
-                               return RGBToHSB(HexToRGB(hex));\r
-                       },\r
-                       RGBToHSB = function (rgb) {\r
-                               var hsb = {\r
-                                       h: 0,\r
-                                       s: 0,\r
-                                       b: 0\r
-                               };\r
-                               var min = Math.min(rgb.r, rgb.g, rgb.b);\r
-                               var max = Math.max(rgb.r, rgb.g, rgb.b);\r
-                               var delta = max - min;\r
-                               hsb.b = max;\r
-                               if (max != 0) {\r
-                                       \r
-                               }\r
-                               hsb.s = max != 0 ? 255 * delta / max : 0;\r
-                               if (hsb.s != 0) {\r
-                                       if (rgb.r == max) {\r
-                                               hsb.h = (rgb.g - rgb.b) / delta;\r
-                                       } else if (rgb.g == max) {\r
-                                               hsb.h = 2 + (rgb.b - rgb.r) / delta;\r
-                                       } else {\r
-                                               hsb.h = 4 + (rgb.r - rgb.g) / delta;\r
-                                       }\r
-                               } else {\r
-                                       hsb.h = -1;\r
-                               }\r
-                               hsb.h *= 60;\r
-                               if (hsb.h < 0) {\r
-                                       hsb.h += 360;\r
-                               }\r
-                               hsb.s *= 100/255;\r
-                               hsb.b *= 100/255;\r
-                               return hsb;\r
-                       },\r
-                       HSBToRGB = function (hsb) {\r
-                               var rgb = {};\r
-                               var h = Math.round(hsb.h);\r
-                               var s = Math.round(hsb.s*255/100);\r
-                               var v = Math.round(hsb.b*255/100);\r
-                               if(s == 0) {\r
-                                       rgb.r = rgb.g = rgb.b = v;\r
-                               } else {\r
-                                       var t1 = v;\r
-                                       var t2 = (255-s)*v/255;\r
-                                       var t3 = (t1-t2)*(h%60)/60;\r
-                                       if(h==360) h = 0;\r
-                                       if(h<60) {rgb.r=t1;     rgb.b=t2; rgb.g=t2+t3}\r
-                                       else if(h<120) {rgb.g=t1; rgb.b=t2;     rgb.r=t1-t3}\r
-                                       else if(h<180) {rgb.g=t1; rgb.r=t2;     rgb.b=t2+t3}\r
-                                       else if(h<240) {rgb.b=t1; rgb.r=t2;     rgb.g=t1-t3}\r
-                                       else if(h<300) {rgb.b=t1; rgb.g=t2;     rgb.r=t2+t3}\r
-                                       else if(h<360) {rgb.r=t1; rgb.g=t2;     rgb.b=t1-t3}\r
-                                       else {rgb.r=0; rgb.g=0; rgb.b=0}\r
-                               }\r
-                               return {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)};\r
-                       },\r
-                       RGBToHex = function (rgb) {\r
-                               var hex = [\r
-                                       rgb.r.toString(16),\r
-                                       rgb.g.toString(16),\r
-                                       rgb.b.toString(16)\r
-                               ];\r
-                               $.each(hex, function (nr, val) {\r
-                                       if (val.length == 1) {\r
-                                               hex[nr] = '0' + val;\r
-                                       }\r
-                               });\r
-                               return hex.join('');\r
-                       },\r
-                       HSBToHex = function (hsb) {\r
-                               return RGBToHex(HSBToRGB(hsb));\r
-                       },\r
-                       restoreOriginal = function () {\r
-                               var cal = $(this).parent();\r
-                               var col = cal.data('colorpicker').origColor;\r
-                               cal.data('colorpicker').color = col;\r
-                               fillRGBFields(col, cal.get(0));\r
-                               fillHexFields(col, cal.get(0));\r
-                               fillHSBFields(col, cal.get(0));\r
-                               setSelector(col, cal.get(0));\r
-                               setHue(col, cal.get(0));\r
-                               setNewColor(col, cal.get(0));\r
-                       };\r
-               return {\r
-                       init: function (opt) {\r
-                               opt = $.extend({}, defaults, opt||{});\r
-                               if (typeof opt.color == 'string') {\r
-                                       opt.color = HexToHSB(opt.color);\r
-                               } else if (opt.color.r != undefined && opt.color.g != undefined && opt.color.b != undefined) {\r
-                                       opt.color = RGBToHSB(opt.color);\r
-                               } else if (opt.color.h != undefined && opt.color.s != undefined && opt.color.b != undefined) {\r
-                                       opt.color = fixHSB(opt.color);\r
-                               } else {\r
-                                       return this;\r
-                               }\r
-                               return this.each(function () {\r
-                                       if (!$(this).data('colorpickerId')) {\r
-                                               var options = $.extend({}, opt);\r
-                                               options.origColor = opt.color;\r
-                                               var id = 'collorpicker_' + parseInt(Math.random() * 1000);\r
-                                               $(this).data('colorpickerId', id);\r
-                                               var cal = $(tpl).attr('id', id);\r
-                                               if (options.flat) {\r
-                                                       cal.appendTo(this).show();\r
-                                               } else {\r
-                                                       cal.appendTo(document.body);\r
-                                               }\r
-                                               options.fields = cal\r
-                                                                                       .find('input')\r
-                                                                                               .bind('keyup', keyDown)\r
-                                                                                               .bind('change', change)\r
-                                                                                               .bind('blur', blur)\r
-                                                                                               .bind('focus', focus);\r
-                                               cal\r
-                                                       .find('span').bind('mousedown', downIncrement).end()\r
-                                                       .find('>div.colorpicker_current_color').bind('click', restoreOriginal);\r
-                                               options.selector = cal.find('div.colorpicker_color').bind('mousedown', downSelector);\r
-                                               options.selectorIndic = options.selector.find('div div');\r
-                                               options.el = this;\r
-                                               options.hue = cal.find('div.colorpicker_hue div');\r
-                                               cal.find('div.colorpicker_hue').bind('mousedown', downHue);\r
-                                               options.newColor = cal.find('div.colorpicker_new_color');\r
-                                               options.currentColor = cal.find('div.colorpicker_current_color');\r
-                                               cal.data('colorpicker', options);\r
-                                               cal.find('div.colorpicker_submit')\r
-                                                       .bind('mouseenter', enterSubmit)\r
-                                                       .bind('mouseleave', leaveSubmit)\r
-                                                       .bind('click', clickSubmit);\r
-                                               fillRGBFields(options.color, cal.get(0));\r
-                                               fillHSBFields(options.color, cal.get(0));\r
-                                               fillHexFields(options.color, cal.get(0));\r
-                                               setHue(options.color, cal.get(0));\r
-                                               setSelector(options.color, cal.get(0));\r
-                                               setCurrentColor(options.color, cal.get(0));\r
-                                               setNewColor(options.color, cal.get(0));\r
-                                               if (options.flat) {\r
-                                                       cal.css({\r
-                                                               position: 'relative',\r
-                                                               display: 'block'\r
-                                                       });\r
-                                               } else {\r
-                                                       $(this).bind(options.eventName, show);\r
-                                               }\r
-                                       }\r
-                               });\r
-                       },\r
-                       showPicker: function() {\r
-                               return this.each( function () {\r
-                                       if ($(this).data('colorpickerId')) {\r
-                                               show.apply(this);\r
-                                       }\r
-                               });\r
-                       },\r
-                       hidePicker: function() {\r
-                               return this.each( function () {\r
-                                       if ($(this).data('colorpickerId')) {\r
-                                               $('#' + $(this).data('colorpickerId')).hide();\r
-                                       }\r
-                               });\r
-                       },\r
-                       setColor: function(col) {\r
-                               if (typeof col == 'string') {\r
-                                       col = HexToHSB(col);\r
-                               } else if (col.r != undefined && col.g != undefined && col.b != undefined) {\r
-                                       col = RGBToHSB(col);\r
-                               } else if (col.h != undefined && col.s != undefined && col.b != undefined) {\r
-                                       col = fixHSB(col);\r
-                               } else {\r
-                                       return this;\r
-                               }\r
-                               return this.each(function(){\r
-                                       if ($(this).data('colorpickerId')) {\r
-                                               var cal = $('#' + $(this).data('colorpickerId'));\r
-                                               cal.data('colorpicker').color = col;\r
-                                               cal.data('colorpicker').origColor = col;\r
-                                               fillRGBFields(col, cal.get(0));\r
-                                               fillHSBFields(col, cal.get(0));\r
-                                               fillHexFields(col, cal.get(0));\r
-                                               setHue(col, cal.get(0));\r
-                                               setSelector(col, cal.get(0));\r
-                                               setCurrentColor(col, cal.get(0));\r
-                                               setNewColor(col, cal.get(0));\r
-                                       }\r
-                               });\r
-                       }\r
-               };\r
-       }();\r
-       $.fn.extend({\r
-               ColorPicker: ColorPicker.init,\r
-               ColorPickerHide: ColorPicker.hidePicker,\r
-               ColorPickerShow: ColorPicker.showPicker,\r
-               ColorPickerSetColor: ColorPicker.setColor\r
-       });\r
+/**
+ *
+ * Color picker
+ * Author: Stefan Petre www.eyecon.ro
+ * 
+ * Dual licensed under the MIT and GPL licenses
+ * 
+ */
+(function ($) {
+       var ColorPicker = function () {
+               var
+                       ids = {},
+                       inAction,
+                       charMin = 65,
+                       visible,
+                       tpl = '<div class="colorpicker"><div class="colorpicker_color"><div><div></div></div></div><div class="colorpicker_hue"><div></div></div><div class="colorpicker_new_color"></div><div class="colorpicker_current_color"></div><div class="colorpicker_hex"><input type="text" maxlength="6" size="6" /></div><div class="colorpicker_rgb_r colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_g colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_h colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_s colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_submit"></div></div>',
+                       defaults = {
+                               eventName: 'click',
+                               onShow: function () {},
+                               onBeforeShow: function(){},
+                               onHide: function () {},
+                               onChange: function () {},
+                               onSubmit: function () {},
+                               color: 'ff0000',
+                               livePreview: true,
+                               flat: false
+                       },
+                       fillRGBFields = function  (hsb, cal) {
+                               var rgb = HSBToRGB(hsb);
+                               $(cal).data('colorpicker').fields
+                                       .eq(1).val(rgb.r).end()
+                                       .eq(2).val(rgb.g).end()
+                                       .eq(3).val(rgb.b).end();
+                       },
+                       fillHSBFields = function  (hsb, cal) {
+                               $(cal).data('colorpicker').fields
+                                       .eq(4).val(hsb.h).end()
+                                       .eq(5).val(hsb.s).end()
+                                       .eq(6).val(hsb.b).end();
+                       },
+                       fillHexFields = function (hsb, cal) {
+                               $(cal).data('colorpicker').fields
+                                       .eq(0).val(HSBToHex(hsb)).end();
+                       },
+                       setSelector = function (hsb, cal) {
+                               $(cal).data('colorpicker').selector.css('backgroundColor', '#' + HSBToHex({h: hsb.h, s: 100, b: 100}));
+                               $(cal).data('colorpicker').selectorIndic.css({
+                                       left: parseInt(150 * hsb.s/100, 10),
+                                       top: parseInt(150 * (100-hsb.b)/100, 10)
+                               });
+                       },
+                       setHue = function (hsb, cal) {
+                               $(cal).data('colorpicker').hue.css('top', parseInt(150 - 150 * hsb.h/360, 10));
+                       },
+                       setCurrentColor = function (hsb, cal) {
+                               $(cal).data('colorpicker').currentColor.css('backgroundColor', '#' + HSBToHex(hsb));
+                       },
+                       setNewColor = function (hsb, cal) {
+                               $(cal).data('colorpicker').newColor.css('backgroundColor', '#' + HSBToHex(hsb));
+                       },
+                       keyDown = function (ev) {
+                               var pressedKey = ev.charCode || ev.keyCode || -1;
+                               if ((pressedKey > charMin && pressedKey <= 90) || pressedKey == 32) {
+                                       return false;
+                               }
+                               var cal = $(this).parent().parent();
+                               if (cal.data('colorpicker').livePreview === true) {
+                                       change.apply(this);
+                               }
+                       },
+                       change = function (ev) {
+                               var cal = $(this).parent().parent(), col;
+                               if (this.parentNode.className.indexOf('_hex') > 0) {
+                                       cal.data('colorpicker').color = col = HexToHSB(fixHex(this.value));
+                               } else if (this.parentNode.className.indexOf('_hsb') > 0) {
+                                       cal.data('colorpicker').color = col = fixHSB({
+                                               h: parseInt(cal.data('colorpicker').fields.eq(4).val(), 10),
+                                               s: parseInt(cal.data('colorpicker').fields.eq(5).val(), 10),
+                                               b: parseInt(cal.data('colorpicker').fields.eq(6).val(), 10)
+                                       });
+                               } else {
+                                       cal.data('colorpicker').color = col = RGBToHSB(fixRGB({
+                                               r: parseInt(cal.data('colorpicker').fields.eq(1).val(), 10),
+                                               g: parseInt(cal.data('colorpicker').fields.eq(2).val(), 10),
+                                               b: parseInt(cal.data('colorpicker').fields.eq(3).val(), 10)
+                                       }));
+                               }
+                               if (ev) {
+                                       fillRGBFields(col, cal.get(0));
+                                       fillHexFields(col, cal.get(0));
+                                       fillHSBFields(col, cal.get(0));
+                               }
+                               setSelector(col, cal.get(0));
+                               setHue(col, cal.get(0));
+                               setNewColor(col, cal.get(0));
+                               cal.data('colorpicker').onChange.apply(cal, [col, HSBToHex(col), HSBToRGB(col)]);
+                       },
+                       blur = function (ev) {
+                               var cal = $(this).parent().parent();
+                               cal.data('colorpicker').fields.parent().removeClass('colorpicker_focus');
+                       },
+                       focus = function () {
+                               charMin = this.parentNode.className.indexOf('_hex') > 0 ? 70 : 65;
+                               $(this).parent().parent().data('colorpicker').fields.parent().removeClass('colorpicker_focus');
+                               $(this).parent().addClass('colorpicker_focus');
+                       },
+                       downIncrement = function (ev) {
+                               var field = $(this).parent().find('input').focus();
+                               var current = {
+                                       el: $(this).parent().addClass('colorpicker_slider'),
+                                       max: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255),
+                                       y: ev.pageY,
+                                       field: field,
+                                       val: parseInt(field.val(), 10),
+                                       preview: $(this).parent().parent().data('colorpicker').livePreview                                      
+                               };
+                               $(document).bind('mouseup', current, upIncrement);
+                               $(document).bind('mousemove', current, moveIncrement);
+                       },
+                       moveIncrement = function (ev) {
+                               ev.data.field.val(Math.max(0, Math.min(ev.data.max, parseInt(ev.data.val + ev.pageY - ev.data.y, 10))));
+                               if (ev.data.preview) {
+                                       change.apply(ev.data.field.get(0), [true]);
+                               }
+                               return false;
+                       },
+                       upIncrement = function (ev) {
+                               change.apply(ev.data.field.get(0), [true]);
+                               ev.data.el.removeClass('colorpicker_slider').find('input').focus();
+                               $(document).unbind('mouseup', upIncrement);
+                               $(document).unbind('mousemove', moveIncrement);
+                               return false;
+                       },
+                       downHue = function (ev) {
+                               var current = {
+                                       cal: $(this).parent(),
+                                       y: $(this).offset().top
+                               };
+                               current.preview = current.cal.data('colorpicker').livePreview;
+                               $(document).bind('mouseup', current, upHue);
+                               $(document).bind('mousemove', current, moveHue);
+                       },
+                       moveHue = function (ev) {
+                               change.apply(
+                                       ev.data.cal.data('colorpicker')
+                                               .fields
+                                               .eq(4)
+                                               .val(parseInt(360*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.y))))/150, 10))
+                                               .get(0),
+                                       [ev.data.preview]
+                               );
+                               return false;
+                       },
+                       upHue = function (ev) {
+                               fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
+                               fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
+                               $(document).unbind('mouseup', upHue);
+                               $(document).unbind('mousemove', moveHue);
+                               return false;
+                       },
+                       downSelector = function (ev) {
+                               var current = {
+                                       cal: $(this).parent(),
+                                       pos: $(this).offset()
+                               };
+                               current.preview = current.cal.data('colorpicker').livePreview;
+                               $(document).bind('mouseup', current, upSelector);
+                               $(document).bind('mousemove', current, moveSelector);
+                       },
+                       moveSelector = function (ev) {
+                               change.apply(
+                                       ev.data.cal.data('colorpicker')
+                                               .fields
+                                               .eq(6)
+                                               .val(parseInt(100*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.pos.top))))/150, 10))
+                                               .end()
+                                               .eq(5)
+                                               .val(parseInt(100*(Math.max(0,Math.min(150,(ev.pageX - ev.data.pos.left))))/150, 10))
+                                               .get(0),
+                                       [ev.data.preview]
+                               );
+                               return false;
+                       },
+                       upSelector = function (ev) {
+                               fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
+                               fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
+                               $(document).unbind('mouseup', upSelector);
+                               $(document).unbind('mousemove', moveSelector);
+                               return false;
+                       },
+                       enterSubmit = function (ev) {
+                               $(this).addClass('colorpicker_focus');
+                       },
+                       leaveSubmit = function (ev) {
+                               $(this).removeClass('colorpicker_focus');
+                       },
+                       clickSubmit = function (ev) {
+                               var cal = $(this).parent();
+                               var col = cal.data('colorpicker').color;
+                               cal.data('colorpicker').origColor = col;
+                               setCurrentColor(col, cal.get(0));
+                               cal.data('colorpicker').onSubmit(col, HSBToHex(col), HSBToRGB(col), cal.data('colorpicker').el);
+                       },
+                       show = function (ev) {
+                               var cal = $('#' + $(this).data('colorpickerId'));
+                               cal.data('colorpicker').onBeforeShow.apply(this, [cal.get(0)]);
+                               var pos = $(this).offset();
+                               var viewPort = getViewport();
+                               var top = pos.top + this.offsetHeight;
+                               var left = pos.left;
+                               if (top + 176 > viewPort.t + viewPort.h) {
+                                       top -= this.offsetHeight + 176;
+                               }
+                               if (left + 356 > viewPort.l + viewPort.w) {
+                                       left -= 356;
+                               }
+                               cal.css({left: left + 'px', top: top + 'px'});
+                               if (cal.data('colorpicker').onShow.apply(this, [cal.get(0)]) != false) {
+                                       cal.show();
+                               }
+                               $(document).bind('mousedown', {cal: cal}, hide);
+                               return false;
+                       },
+                       hide = function (ev) {
+                               if (!isChildOf(ev.data.cal.get(0), ev.target, ev.data.cal.get(0))) {
+                                       if (ev.data.cal.data('colorpicker').onHide.apply(this, [ev.data.cal.get(0)]) != false) {
+                                               ev.data.cal.hide();
+                                       }
+                                       $(document).unbind('mousedown', hide);
+                               }
+                       },
+                       isChildOf = function(parentEl, el, container) {
+                               if (parentEl == el) {
+                                       return true;
+                               }
+                               if (parentEl.contains) {
+                                       return parentEl.contains(el);
+                               }
+                               if ( parentEl.compareDocumentPosition ) {
+                                       return !!(parentEl.compareDocumentPosition(el) & 16);
+                               }
+                               var prEl = el.parentNode;
+                               while(prEl && prEl != container) {
+                                       if (prEl == parentEl)
+                                               return true;
+                                       prEl = prEl.parentNode;
+                               }
+                               return false;
+                       },
+                       getViewport = function () {
+                               var m = document.compatMode == 'CSS1Compat';
+                               return {
+                                       l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft),
+                                       t : window.pageYOffset || (m ? document.documentElement.scrollTop : document.body.scrollTop),
+                                       w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth),
+                                       h : window.innerHeight || (m ? document.documentElement.clientHeight : document.body.clientHeight)
+                               };
+                       },
+                       fixHSB = function (hsb) {
+                               return {
+                                       h: Math.min(360, Math.max(0, hsb.h)),
+                                       s: Math.min(100, Math.max(0, hsb.s)),
+                                       b: Math.min(100, Math.max(0, hsb.b))
+                               };
+                       }, 
+                       fixRGB = function (rgb) {
+                               return {
+                                       r: Math.min(255, Math.max(0, rgb.r)),
+                                       g: Math.min(255, Math.max(0, rgb.g)),
+                                       b: Math.min(255, Math.max(0, rgb.b))
+                               };
+                       },
+                       fixHex = function (hex) {
+                               var len = 6 - hex.length;
+                               if (len > 0) {
+                                       var o = [];
+                                       for (var i=0; i<len; i++) {
+                                               o.push('0');
+                                       }
+                                       o.push(hex);
+                                       hex = o.join('');
+                               }
+                               return hex;
+                       }, 
+                       HexToRGB = function (hex) {
+                               var hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);
+                               return {r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF)};
+                       },
+                       HexToHSB = function (hex) {
+                               return RGBToHSB(HexToRGB(hex));
+                       },
+                       RGBToHSB = function (rgb) {
+                               var hsb = {
+                                       h: 0,
+                                       s: 0,
+                                       b: 0
+                               };
+                               var min = Math.min(rgb.r, rgb.g, rgb.b);
+                               var max = Math.max(rgb.r, rgb.g, rgb.b);
+                               var delta = max - min;
+                               hsb.b = max;
+                               if (max != 0) {
+                                       
+                               }
+                               hsb.s = max != 0 ? 255 * delta / max : 0;
+                               if (hsb.s != 0) {
+                                       if (rgb.r == max) {
+                                               hsb.h = (rgb.g - rgb.b) / delta;
+                                       } else if (rgb.g == max) {
+                                               hsb.h = 2 + (rgb.b - rgb.r) / delta;
+                                       } else {
+                                               hsb.h = 4 + (rgb.r - rgb.g) / delta;
+                                       }
+                               } else {
+                                       hsb.h = -1;
+                               }
+                               hsb.h *= 60;
+                               if (hsb.h < 0) {
+                                       hsb.h += 360;
+                               }
+                               hsb.s *= 100/255;
+                               hsb.b *= 100/255;
+                               return hsb;
+                       },
+                       HSBToRGB = function (hsb) {
+                               var rgb = {};
+                               var h = Math.round(hsb.h);
+                               var s = Math.round(hsb.s*255/100);
+                               var v = Math.round(hsb.b*255/100);
+                               if(s == 0) {
+                                       rgb.r = rgb.g = rgb.b = v;
+                               } else {
+                                       var t1 = v;
+                                       var t2 = (255-s)*v/255;
+                                       var t3 = (t1-t2)*(h%60)/60;
+                                       if(h==360) h = 0;
+                                       if(h<60) {rgb.r=t1;     rgb.b=t2; rgb.g=t2+t3}
+                                       else if(h<120) {rgb.g=t1; rgb.b=t2;     rgb.r=t1-t3}
+                                       else if(h<180) {rgb.g=t1; rgb.r=t2;     rgb.b=t2+t3}
+                                       else if(h<240) {rgb.b=t1; rgb.r=t2;     rgb.g=t1-t3}
+                                       else if(h<300) {rgb.b=t1; rgb.g=t2;     rgb.r=t2+t3}
+                                       else if(h<360) {rgb.r=t1; rgb.g=t2;     rgb.b=t1-t3}
+                                       else {rgb.r=0; rgb.g=0; rgb.b=0}
+                               }
+                               return {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)};
+                       },
+                       RGBToHex = function (rgb) {
+                               var hex = [
+                                       rgb.r.toString(16),
+                                       rgb.g.toString(16),
+                                       rgb.b.toString(16)
+                               ];
+                               $.each(hex, function (nr, val) {
+                                       if (val.length == 1) {
+                                               hex[nr] = '0' + val;
+                                       }
+                               });
+                               return hex.join('');
+                       },
+                       HSBToHex = function (hsb) {
+                               return RGBToHex(HSBToRGB(hsb));
+                       },
+                       restoreOriginal = function () {
+                               var cal = $(this).parent();
+                               var col = cal.data('colorpicker').origColor;
+                               cal.data('colorpicker').color = col;
+                               fillRGBFields(col, cal.get(0));
+                               fillHexFields(col, cal.get(0));
+                               fillHSBFields(col, cal.get(0));
+                               setSelector(col, cal.get(0));
+                               setHue(col, cal.get(0));
+                               setNewColor(col, cal.get(0));
+                       };
+               return {
+                       init: function (opt) {
+                               opt = $.extend({}, defaults, opt||{});
+                               if (typeof opt.color == 'string') {
+                                       opt.color = HexToHSB(opt.color);
+                               } else if (opt.color.r != undefined && opt.color.g != undefined && opt.color.b != undefined) {
+                                       opt.color = RGBToHSB(opt.color);
+                               } else if (opt.color.h != undefined && opt.color.s != undefined && opt.color.b != undefined) {
+                                       opt.color = fixHSB(opt.color);
+                               } else {
+                                       return this;
+                               }
+                               return this.each(function () {
+                                       if (!$(this).data('colorpickerId')) {
+                                               var options = $.extend({}, opt);
+                                               options.origColor = opt.color;
+                                               var id = 'collorpicker_' + parseInt(Math.random() * 1000);
+                                               $(this).data('colorpickerId', id);
+                                               var cal = $(tpl).attr('id', id);
+                                               if (options.flat) {
+                                                       cal.appendTo(this).show();
+                                               } else {
+                                                       cal.appendTo(document.body);
+                                               }
+                                               options.fields = cal
+                                                                                       .find('input')
+                                                                                               .bind('keyup', keyDown)
+                                                                                               .bind('change', change)
+                                                                                               .bind('blur', blur)
+                                                                                               .bind('focus', focus);
+                                               cal
+                                                       .find('span').bind('mousedown', downIncrement).end()
+                                                       .find('>div.colorpicker_current_color').bind('click', restoreOriginal);
+                                               options.selector = cal.find('div.colorpicker_color').bind('mousedown', downSelector);
+                                               options.selectorIndic = options.selector.find('div div');
+                                               options.el = this;
+                                               options.hue = cal.find('div.colorpicker_hue div');
+                                               cal.find('div.colorpicker_hue').bind('mousedown', downHue);
+                                               options.newColor = cal.find('div.colorpicker_new_color');
+                                               options.currentColor = cal.find('div.colorpicker_current_color');
+                                               cal.data('colorpicker', options);
+                                               cal.find('div.colorpicker_submit')
+                                                       .bind('mouseenter', enterSubmit)
+                                                       .bind('mouseleave', leaveSubmit)
+                                                       .bind('click', clickSubmit);
+                                               fillRGBFields(options.color, cal.get(0));
+                                               fillHSBFields(options.color, cal.get(0));
+                                               fillHexFields(options.color, cal.get(0));
+                                               setHue(options.color, cal.get(0));
+                                               setSelector(options.color, cal.get(0));
+                                               setCurrentColor(options.color, cal.get(0));
+                                               setNewColor(options.color, cal.get(0));
+                                               if (options.flat) {
+                                                       cal.css({
+                                                               position: 'relative',
+                                                               display: 'block'
+                                                       });
+                                               } else {
+                                                       $(this).bind(options.eventName, show);
+                                               }
+                                       }
+                               });
+                       },
+                       showPicker: function() {
+                               return this.each( function () {
+                                       if ($(this).data('colorpickerId')) {
+                                               show.apply(this);
+                                       }
+                               });
+                       },
+                       hidePicker: function() {
+                               return this.each( function () {
+                                       if ($(this).data('colorpickerId')) {
+                                               $('#' + $(this).data('colorpickerId')).hide();
+                                       }
+                               });
+                       },
+                       setColor: function(col) {
+                               if (typeof col == 'string') {
+                                       col = HexToHSB(col);
+                               } else if (col.r != undefined && col.g != undefined && col.b != undefined) {
+                                       col = RGBToHSB(col);
+                               } else if (col.h != undefined && col.s != undefined && col.b != undefined) {
+                                       col = fixHSB(col);
+                               } else {
+                                       return this;
+                               }
+                               return this.each(function(){
+                                       if ($(this).data('colorpickerId')) {
+                                               var cal = $('#' + $(this).data('colorpickerId'));
+                                               cal.data('colorpicker').color = col;
+                                               cal.data('colorpicker').origColor = col;
+                                               fillRGBFields(col, cal.get(0));
+                                               fillHSBFields(col, cal.get(0));
+                                               fillHexFields(col, cal.get(0));
+                                               setHue(col, cal.get(0));
+                                               setSelector(col, cal.get(0));
+                                               setCurrentColor(col, cal.get(0));
+                                               setNewColor(col, cal.get(0));
+                                       }
+                               });
+                       }
+               };
+       }();
+       $.fn.extend({
+               ColorPicker: ColorPicker.init,
+               ColorPickerHide: ColorPicker.hidePicker,
+               ColorPickerShow: ColorPicker.showPicker,
+               ColorPickerSetColor: ColorPicker.setColor
+       });
 })(jQuery)
\ No newline at end of file
index ea70e64..8a281dc 100644 (file)
@@ -1,34 +1,34 @@
-/**\r
- *\r
- * Zoomimage\r
- * Author: Stefan Petre www.eyecon.ro\r
- * \r
- */\r
-(function($){\r
-       var EYE = window.EYE = function() {\r
-               var _registered = {\r
-                       init: []\r
-               };\r
-               return {\r
-                       init: function() {\r
-                               $.each(_registered.init, function(nr, fn){\r
-                                       fn.call();\r
-                               });\r
-                       },\r
-                       extend: function(prop) {\r
-                               for (var i in prop) {\r
-                                       if (prop[i] != undefined) {\r
-                                               this[i] = prop[i];\r
-                                       }\r
-                               }\r
-                       },\r
-                       register: function(fn, type) {\r
-                               if (!_registered[type]) {\r
-                                       _registered[type] = [];\r
-                               }\r
-                               _registered[type].push(fn);\r
-                       }\r
-               };\r
-       }();\r
-       $(EYE.init);\r
-})(jQuery);\r
+/**
+ *
+ * Zoomimage
+ * Author: Stefan Petre www.eyecon.ro
+ * 
+ */
+(function($){
+       var EYE = window.EYE = function() {
+               var _registered = {
+                       init: []
+               };
+               return {
+                       init: function() {
+                               $.each(_registered.init, function(nr, fn){
+                                       fn.call();
+                               });
+                       },
+                       extend: function(prop) {
+                               for (var i in prop) {
+                                       if (prop[i] != undefined) {
+                                               this[i] = prop[i];
+                                       }
+                               }
+                       },
+                       register: function(fn, type) {
+                               if (!_registered[type]) {
+                                       _registered[type] = [];
+                               }
+                               _registered[type].push(fn);
+                       }
+               };
+       }();
+       $(EYE.init);
+})(jQuery);
index e0dfb8f..56975f3 100644 (file)
@@ -1,67 +1,67 @@
-(function($){\r
-       var initLayout = function() {\r
-               var hash = window.location.hash.replace('#', '');\r
-               var currentTab = $('ul.navigationTabs a')\r
-                                                       .bind('click', showTab)\r
-                                                       .filter('a[rel=' + hash + ']');\r
-               if (currentTab.size() == 0) {\r
-                       currentTab = $('ul.navigationTabs a:first');\r
-               }\r
-               showTab.apply(currentTab.get(0));\r
-               $('#colorpickerHolder').ColorPicker({flat: true});\r
-               $('#colorpickerHolder2').ColorPicker({\r
-                       flat: true,\r
-                       color: '#00ff00',\r
-                       onSubmit: function(hsb, hex, rgb) {\r
-                               $('#colorSelector2 div').css('backgroundColor', '#' + hex);\r
-                       }\r
-               });\r
-               $('#colorpickerHolder2>div').css('position', 'absolute');\r
-               var widt = false;\r
-               $('#colorSelector2').bind('click', function() {\r
-                       $('#colorpickerHolder2').stop().animate({height: widt ? 0 : 173}, 500);\r
-                       widt = !widt;\r
-               });\r
-               $('#colorpickerField1, #colorpickerField2, #colorpickerField3').ColorPicker({\r
-                       onSubmit: function(hsb, hex, rgb, el) {\r
-                               $(el).val(hex);\r
-                               $(el).ColorPickerHide();\r
-                       },\r
-                       onBeforeShow: function () {\r
-                               $(this).ColorPickerSetColor(this.value);\r
-                       }\r
-               })\r
-               .bind('keyup', function(){\r
-                       $(this).ColorPickerSetColor(this.value);\r
-               });\r
-               $('#colorSelector').ColorPicker({\r
-                       color: '#0000ff',\r
-                       onShow: function (colpkr) {\r
-                               $(colpkr).fadeIn(500);\r
-                               return false;\r
-                       },\r
-                       onHide: function (colpkr) {\r
-                               $(colpkr).fadeOut(500);\r
-                               return false;\r
-                       },\r
-                       onChange: function (hsb, hex, rgb) {\r
-                               $('#colorSelector div').css('backgroundColor', '#' + hex);\r
-                       }\r
-               });\r
-       };\r
-       \r
-       var showTab = function(e) {\r
-               var tabIndex = $('ul.navigationTabs a')\r
-                                                       .removeClass('active')\r
-                                                       .index(this);\r
-               $(this)\r
-                       .addClass('active')\r
-                       .blur();\r
-               $('div.tab')\r
-                       .hide()\r
-                               .eq(tabIndex)\r
-                               .show();\r
-       };\r
-       \r
-       EYE.register(initLayout, 'init');\r
+(function($){
+       var initLayout = function() {
+               var hash = window.location.hash.replace('#', '');
+               var currentTab = $('ul.navigationTabs a')
+                                                       .bind('click', showTab)
+                                                       .filter('a[rel=' + hash + ']');
+               if (currentTab.size() == 0) {
+                       currentTab = $('ul.navigationTabs a:first');
+               }
+               showTab.apply(currentTab.get(0));
+               $('#colorpickerHolder').ColorPicker({flat: true});
+               $('#colorpickerHolder2').ColorPicker({
+                       flat: true,
+                       color: '#00ff00',
+                       onSubmit: function(hsb, hex, rgb) {
+                               $('#colorSelector2 div').css('backgroundColor', '#' + hex);
+                       }
+               });
+               $('#colorpickerHolder2>div').css('position', 'absolute');
+               var widt = false;
+               $('#colorSelector2').bind('click', function() {
+                       $('#colorpickerHolder2').stop().animate({height: widt ? 0 : 173}, 500);
+                       widt = !widt;
+               });
+               $('#colorpickerField1, #colorpickerField2, #colorpickerField3').ColorPicker({
+                       onSubmit: function(hsb, hex, rgb, el) {
+                               $(el).val(hex);
+                               $(el).ColorPickerHide();
+                       },
+                       onBeforeShow: function () {
+                               $(this).ColorPickerSetColor(this.value);
+                       }
+               })
+               .bind('keyup', function(){
+                       $(this).ColorPickerSetColor(this.value);
+               });
+               $('#colorSelector').ColorPicker({
+                       color: '#0000ff',
+                       onShow: function (colpkr) {
+                               $(colpkr).fadeIn(500);
+                               return false;
+                       },
+                       onHide: function (colpkr) {
+                               $(colpkr).fadeOut(500);
+                               return false;
+                       },
+                       onChange: function (hsb, hex, rgb) {
+                               $('#colorSelector div').css('backgroundColor', '#' + hex);
+                       }
+               });
+       };
+       
+       var showTab = function(e) {
+               var tabIndex = $('ul.navigationTabs a')
+                                                       .removeClass('active')
+                                                       .index(this);
+               $(this)
+                       .addClass('active')
+                       .blur();
+               $('div.tab')
+                       .hide()
+                               .eq(tabIndex)
+                               .show();
+       };
+       
+       EYE.register(initLayout, 'init');
 })(jQuery)
\ No newline at end of file
index cc7ce14..d9be853 100644 (file)
-/**\r
- *\r
- * Utilities\r
- * Author: Stefan Petre www.eyecon.ro\r
- * \r
- */\r
-(function($) {\r
-EYE.extend({\r
-       getPosition : function(e, forceIt)\r
-       {\r
-               var x = 0;\r
-               var y = 0;\r
-               var es = e.style;\r
-               var restoreStyles = false;\r
-               if (forceIt && jQuery.curCSS(e,'display') == 'none') {\r
-                       var oldVisibility = es.visibility;\r
-                       var oldPosition = es.position;\r
-                       restoreStyles = true;\r
-                       es.visibility = 'hidden';\r
-                       es.display = 'block';\r
-                       es.position = 'absolute';\r
-               }\r
-               var el = e;\r
-               if (el.getBoundingClientRect) { // IE\r
-                       var box = el.getBoundingClientRect();\r
-                       x = box.left + Math.max(document.documentElement.scrollLeft, document.body.scrollLeft) - 2;\r
-                       y = box.top + Math.max(document.documentElement.scrollTop, document.body.scrollTop) - 2;\r
-               } else {\r
-                       x = el.offsetLeft;\r
-                       y = el.offsetTop;\r
-                       el = el.offsetParent;\r
-                       if (e != el) {\r
-                               while (el) {\r
-                                       x += el.offsetLeft;\r
-                                       y += el.offsetTop;\r
-                                       el = el.offsetParent;\r
-                               }\r
-                       }\r
-                       if (jQuery.browser.safari && jQuery.curCSS(e, 'position') == 'absolute' ) {\r
-                               x -= document.body.offsetLeft;\r
-                               y -= document.body.offsetTop;\r
-                       }\r
-                       el = e.parentNode;\r
-                       while (el && el.tagName.toUpperCase() != 'BODY' && el.tagName.toUpperCase() != 'HTML') \r
-                       {\r
-                               if (jQuery.curCSS(el, 'display') != 'inline') {\r
-                                       x -= el.scrollLeft;\r
-                                       y -= el.scrollTop;\r
-                               }\r
-                               el = el.parentNode;\r
-                       }\r
-               }\r
-               if (restoreStyles == true) {\r
-                       es.display = 'none';\r
-                       es.position = oldPosition;\r
-                       es.visibility = oldVisibility;\r
-               }\r
-               return {x:x, y:y};\r
-       },\r
-       getSize : function(e)\r
-       {\r
-               var w = parseInt(jQuery.curCSS(e,'width'), 10);\r
-               var h = parseInt(jQuery.curCSS(e,'height'), 10);\r
-               var wb = 0;\r
-               var hb = 0;\r
-               if (jQuery.curCSS(e, 'display') != 'none') {\r
-                       wb = e.offsetWidth;\r
-                       hb = e.offsetHeight;\r
-               } else {\r
-                       var es = e.style;\r
-                       var oldVisibility = es.visibility;\r
-                       var oldPosition = es.position;\r
-                       es.visibility = 'hidden';\r
-                       es.display = 'block';\r
-                       es.position = 'absolute';\r
-                       wb = e.offsetWidth;\r
-                       hb = e.offsetHeight;\r
-                       es.display = 'none';\r
-                       es.position = oldPosition;\r
-                       es.visibility = oldVisibility;\r
-               }\r
-               return {w:w, h:h, wb:wb, hb:hb};\r
-       },\r
-       getClient : function(e)\r
-       {\r
-               var h, w;\r
-               if (e) {\r
-                       w = e.clientWidth;\r
-                       h = e.clientHeight;\r
-               } else {\r
-                       var de = document.documentElement;\r
-                       w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;\r
-                       h = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;\r
-               }\r
-               return {w:w,h:h};\r
-       },\r
-       getScroll : function (e)\r
-       {\r
-               var t=0, l=0, w=0, h=0, iw=0, ih=0;\r
-               if (e && e.nodeName.toLowerCase() != 'body') {\r
-                       t = e.scrollTop;\r
-                       l = e.scrollLeft;\r
-                       w = e.scrollWidth;\r
-                       h = e.scrollHeight;\r
-               } else  {\r
-                       if (document.documentElement) {\r
-                               t = document.documentElement.scrollTop;\r
-                               l = document.documentElement.scrollLeft;\r
-                               w = document.documentElement.scrollWidth;\r
-                               h = document.documentElement.scrollHeight;\r
-                       } else if (document.body) {\r
-                               t = document.body.scrollTop;\r
-                               l = document.body.scrollLeft;\r
-                               w = document.body.scrollWidth;\r
-                               h = document.body.scrollHeight;\r
-                       }\r
-                       if (typeof pageYOffset != 'undefined') {\r
-                               t = pageYOffset;\r
-                               l = pageXOffset;\r
-                       }\r
-                       iw = self.innerWidth||document.documentElement.clientWidth||document.body.clientWidth||0;\r
-                       ih = self.innerHeight||document.documentElement.clientHeight||document.body.clientHeight||0;\r
-               }\r
-               return { t: t, l: l, w: w, h: h, iw: iw, ih: ih };\r
-       },\r
-       getMargins : function(e, toInteger)\r
-       {\r
-               var t = jQuery.curCSS(e,'marginTop') || '';\r
-               var r = jQuery.curCSS(e,'marginRight') || '';\r
-               var b = jQuery.curCSS(e,'marginBottom') || '';\r
-               var l = jQuery.curCSS(e,'marginLeft') || '';\r
-               if (toInteger)\r
-                       return {\r
-                               t: parseInt(t, 10)||0,\r
-                               r: parseInt(r, 10)||0,\r
-                               b: parseInt(b, 10)||0,\r
-                               l: parseInt(l, 10)\r
-                       };\r
-               else\r
-                       return {t: t, r: r,     b: b, l: l};\r
-       },\r
-       getPadding : function(e, toInteger)\r
-       {\r
-               var t = jQuery.curCSS(e,'paddingTop') || '';\r
-               var r = jQuery.curCSS(e,'paddingRight') || '';\r
-               var b = jQuery.curCSS(e,'paddingBottom') || '';\r
-               var l = jQuery.curCSS(e,'paddingLeft') || '';\r
-               if (toInteger)\r
-                       return {\r
-                               t: parseInt(t, 10)||0,\r
-                               r: parseInt(r, 10)||0,\r
-                               b: parseInt(b, 10)||0,\r
-                               l: parseInt(l, 10)\r
-                       };\r
-               else\r
-                       return {t: t, r: r,     b: b, l: l};\r
-       },\r
-       getBorder : function(e, toInteger)\r
-       {\r
-               var t = jQuery.curCSS(e,'borderTopWidth') || '';\r
-               var r = jQuery.curCSS(e,'borderRightWidth') || '';\r
-               var b = jQuery.curCSS(e,'borderBottomWidth') || '';\r
-               var l = jQuery.curCSS(e,'borderLeftWidth') || '';\r
-               if (toInteger)\r
-                       return {\r
-                               t: parseInt(t, 10)||0,\r
-                               r: parseInt(r, 10)||0,\r
-                               b: parseInt(b, 10)||0,\r
-                               l: parseInt(l, 10)||0\r
-                       };\r
-               else\r
-                       return {t: t, r: r,     b: b, l: l};\r
-       },\r
-       traverseDOM : function(nodeEl, func)\r
-       {\r
-               func(nodeEl);\r
-               nodeEl = nodeEl.firstChild;\r
-               while(nodeEl){\r
-                       EYE.traverseDOM(nodeEl, func);\r
-                       nodeEl = nodeEl.nextSibling;\r
-               }\r
-       },\r
-       getInnerWidth :  function(el, scroll) {\r
-               var offsetW = el.offsetWidth;\r
-               return scroll ? Math.max(el.scrollWidth,offsetW) - offsetW + el.clientWidth:el.clientWidth;\r
-       },\r
-       getInnerHeight : function(el, scroll) {\r
-               var offsetH = el.offsetHeight;\r
-               return scroll ? Math.max(el.scrollHeight,offsetH) - offsetH + el.clientHeight:el.clientHeight;\r
-       },\r
-       getExtraWidth : function(el) {\r
-               if($.boxModel)\r
-                       return (parseInt($.curCSS(el, 'paddingLeft'))||0)\r
-                               + (parseInt($.curCSS(el, 'paddingRight'))||0)\r
-                               + (parseInt($.curCSS(el, 'borderLeftWidth'))||0)\r
-                               + (parseInt($.curCSS(el, 'borderRightWidth'))||0);\r
-               return 0;\r
-       },\r
-       getExtraHeight : function(el) {\r
-               if($.boxModel)\r
-                       return (parseInt($.curCSS(el, 'paddingTop'))||0)\r
-                               + (parseInt($.curCSS(el, 'paddingBottom'))||0)\r
-                               + (parseInt($.curCSS(el, 'borderTopWidth'))||0)\r
-                               + (parseInt($.curCSS(el, 'borderBottomWidth'))||0);\r
-               return 0;\r
-       },\r
-       isChildOf: function(parentEl, el, container) {\r
-               if (parentEl == el) {\r
-                       return true;\r
-               }\r
-               if (!el || !el.nodeType || el.nodeType != 1) {\r
-                       return false;\r
-               }\r
-               if (parentEl.contains && !$.browser.safari) {\r
-                       return parentEl.contains(el);\r
-               }\r
-               if ( parentEl.compareDocumentPosition ) {\r
-                       return !!(parentEl.compareDocumentPosition(el) & 16);\r
-               }\r
-               var prEl = el.parentNode;\r
-               while(prEl && prEl != container) {\r
-                       if (prEl == parentEl)\r
-                               return true;\r
-                       prEl = prEl.parentNode;\r
-               }\r
-               return false;\r
-       },\r
-       centerEl : function(el, axis)\r
-       {\r
-               var clientScroll = EYE.getScroll();\r
-               var size = EYE.getSize(el);\r
-               if (!axis || axis == 'vertically')\r
-                       $(el).css(\r
-                               {\r
-                                       top: clientScroll.t + ((Math.min(clientScroll.h,clientScroll.ih) - size.hb)/2) + 'px'\r
-                               }\r
-                       );\r
-               if (!axis || axis == 'horizontally')\r
-                       $(el).css(\r
-                               {\r
-                                       left: clientScroll.l + ((Math.min(clientScroll.w,clientScroll.iw) - size.wb)/2) + 'px'\r
-                               }\r
-                       );\r
-       }\r
-});\r
-if (!$.easing.easeout) {\r
-       $.easing.easeout = function(p, n, firstNum, delta, duration) {\r
-               return -delta * ((n=n/duration-1)*n*n*n - 1) + firstNum;\r
-       };\r
-}\r
-       \r
+/**
+ *
+ * Utilities
+ * Author: Stefan Petre www.eyecon.ro
+ * 
+ */
+(function($) {
+EYE.extend({
+       getPosition : function(e, forceIt)
+       {
+               var x = 0;
+               var y = 0;
+               var es = e.style;
+               var restoreStyles = false;
+               if (forceIt && jQuery.curCSS(e,'display') == 'none') {
+                       var oldVisibility = es.visibility;
+                       var oldPosition = es.position;
+                       restoreStyles = true;
+                       es.visibility = 'hidden';
+                       es.display = 'block';
+                       es.position = 'absolute';
+               }
+               var el = e;
+               if (el.getBoundingClientRect) { // IE
+                       var box = el.getBoundingClientRect();
+                       x = box.left + Math.max(document.documentElement.scrollLeft, document.body.scrollLeft) - 2;
+                       y = box.top + Math.max(document.documentElement.scrollTop, document.body.scrollTop) - 2;
+               } else {
+                       x = el.offsetLeft;
+                       y = el.offsetTop;
+                       el = el.offsetParent;
+                       if (e != el) {
+                               while (el) {
+                                       x += el.offsetLeft;
+                                       y += el.offsetTop;
+                                       el = el.offsetParent;
+                               }
+                       }
+                       if (jQuery.browser.safari && jQuery.curCSS(e, 'position') == 'absolute' ) {
+                               x -= document.body.offsetLeft;
+                               y -= document.body.offsetTop;
+                       }
+                       el = e.parentNode;
+                       while (el && el.tagName.toUpperCase() != 'BODY' && el.tagName.toUpperCase() != 'HTML') 
+                       {
+                               if (jQuery.curCSS(el, 'display') != 'inline') {
+                                       x -= el.scrollLeft;
+                                       y -= el.scrollTop;
+                               }
+                               el = el.parentNode;
+                       }
+               }
+               if (restoreStyles == true) {
+                       es.display = 'none';
+                       es.position = oldPosition;
+                       es.visibility = oldVisibility;
+               }
+               return {x:x, y:y};
+       },
+       getSize : function(e)
+       {
+               var w = parseInt(jQuery.curCSS(e,'width'), 10);
+               var h = parseInt(jQuery.curCSS(e,'height'), 10);
+               var wb = 0;
+               var hb = 0;
+               if (jQuery.curCSS(e, 'display') != 'none') {
+                       wb = e.offsetWidth;
+                       hb = e.offsetHeight;
+               } else {
+                       var es = e.style;
+                       var oldVisibility = es.visibility;
+                       var oldPosition = es.position;
+                       es.visibility = 'hidden';
+                       es.display = 'block';
+                       es.position = 'absolute';
+                       wb = e.offsetWidth;
+                       hb = e.offsetHeight;
+                       es.display = 'none';
+                       es.position = oldPosition;
+                       es.visibility = oldVisibility;
+               }
+               return {w:w, h:h, wb:wb, hb:hb};
+       },
+       getClient : function(e)
+       {
+               var h, w;
+               if (e) {
+                       w = e.clientWidth;
+                       h = e.clientHeight;
+               } else {
+                       var de = document.documentElement;
+                       w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
+                       h = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;
+               }
+               return {w:w,h:h};
+       },
+       getScroll : function (e)
+       {
+               var t=0, l=0, w=0, h=0, iw=0, ih=0;
+               if (e && e.nodeName.toLowerCase() != 'body') {
+                       t = e.scrollTop;
+                       l = e.scrollLeft;
+                       w = e.scrollWidth;
+                       h = e.scrollHeight;
+               } else  {
+                       if (document.documentElement) {
+                               t = document.documentElement.scrollTop;
+                               l = document.documentElement.scrollLeft;
+                               w = document.documentElement.scrollWidth;
+                               h = document.documentElement.scrollHeight;
+                       } else if (document.body) {
+                               t = document.body.scrollTop;
+                               l = document.body.scrollLeft;
+                               w = document.body.scrollWidth;
+                               h = document.body.scrollHeight;
+                       }
+                       if (typeof pageYOffset != 'undefined') {
+                               t = pageYOffset;
+                               l = pageXOffset;
+                       }
+                       iw = self.innerWidth||document.documentElement.clientWidth||document.body.clientWidth||0;
+                       ih = self.innerHeight||document.documentElement.clientHeight||document.body.clientHeight||0;
+               }
+               return { t: t, l: l, w: w, h: h, iw: iw, ih: ih };
+       },
+       getMargins : function(e, toInteger)
+       {
+               var t = jQuery.curCSS(e,'marginTop') || '';
+               var r = jQuery.curCSS(e,'marginRight') || '';
+               var b = jQuery.curCSS(e,'marginBottom') || '';
+               var l = jQuery.curCSS(e,'marginLeft') || '';
+               if (toInteger)
+                       return {
+                               t: parseInt(t, 10)||0,
+                               r: parseInt(r, 10)||0,
+                               b: parseInt(b, 10)||0,
+                               l: parseInt(l, 10)
+                       };
+               else
+                       return {t: t, r: r,     b: b, l: l};
+       },
+       getPadding : function(e, toInteger)
+       {
+               var t = jQuery.curCSS(e,'paddingTop') || '';
+               var r = jQuery.curCSS(e,'paddingRight') || '';
+               var b = jQuery.curCSS(e,'paddingBottom') || '';
+               var l = jQuery.curCSS(e,'paddingLeft') || '';
+               if (toInteger)
+                       return {
+                               t: parseInt(t, 10)||0,
+                               r: parseInt(r, 10)||0,
+                               b: parseInt(b, 10)||0,
+                               l: parseInt(l, 10)
+                       };
+               else
+                       return {t: t, r: r,     b: b, l: l};
+       },
+       getBorder : function(e, toInteger)
+       {
+               var t = jQuery.curCSS(e,'borderTopWidth') || '';
+               var r = jQuery.curCSS(e,'borderRightWidth') || '';
+               var b = jQuery.curCSS(e,'borderBottomWidth') || '';
+               var l = jQuery.curCSS(e,'borderLeftWidth') || '';
+               if (toInteger)
+                       return {
+                               t: parseInt(t, 10)||0,
+                               r: parseInt(r, 10)||0,
+                               b: parseInt(b, 10)||0,
+                               l: parseInt(l, 10)||0
+                       };
+               else
+                       return {t: t, r: r,     b: b, l: l};
+       },
+       traverseDOM : function(nodeEl, func)
+       {
+               func(nodeEl);
+               nodeEl = nodeEl.firstChild;
+               while(nodeEl){
+                       EYE.traverseDOM(nodeEl, func);
+                       nodeEl = nodeEl.nextSibling;
+               }
+       },
+       getInnerWidth :  function(el, scroll) {
+               var offsetW = el.offsetWidth;
+               return scroll ? Math.max(el.scrollWidth,offsetW) - offsetW + el.clientWidth:el.clientWidth;
+       },
+       getInnerHeight : function(el, scroll) {
+               var offsetH = el.offsetHeight;
+               return scroll ? Math.max(el.scrollHeight,offsetH) - offsetH + el.clientHeight:el.clientHeight;
+       },
+       getExtraWidth : function(el) {
+               if($.boxModel)
+                       return (parseInt($.curCSS(el, 'paddingLeft'))||0)
+                               + (parseInt($.curCSS(el, 'paddingRight'))||0)
+                               + (parseInt($.curCSS(el, 'borderLeftWidth'))||0)
+                               + (parseInt($.curCSS(el, 'borderRightWidth'))||0);
+               return 0;
+       },
+       getExtraHeight : function(el) {
+               if($.boxModel)
+                       return (parseInt($.curCSS(el, 'paddingTop'))||0)
+                               + (parseInt($.curCSS(el, 'paddingBottom'))||0)
+                               + (parseInt($.curCSS(el, 'borderTopWidth'))||0)
+                               + (parseInt($.curCSS(el, 'borderBottomWidth'))||0);
+               return 0;
+       },
+       isChildOf: function(parentEl, el, container) {
+               if (parentEl == el) {
+                       return true;
+               }
+               if (!el || !el.nodeType || el.nodeType != 1) {
+                       return false;
+               }
+               if (parentEl.contains && !$.browser.safari) {
+                       return parentEl.contains(el);
+               }
+               if ( parentEl.compareDocumentPosition ) {
+                       return !!(parentEl.compareDocumentPosition(el) & 16);
+               }
+               var prEl = el.parentNode;
+               while(prEl && prEl != container) {
+                       if (prEl == parentEl)
+                               return true;
+                       prEl = prEl.parentNode;
+               }
+               return false;
+       },
+       centerEl : function(el, axis)
+       {
+               var clientScroll = EYE.getScroll();
+               var size = EYE.getSize(el);
+               if (!axis || axis == 'vertically')
+                       $(el).css(
+                               {
+                                       top: clientScroll.t + ((Math.min(clientScroll.h,clientScroll.ih) - size.hb)/2) + 'px'
+                               }
+                       );
+               if (!axis || axis == 'horizontally')
+                       $(el).css(
+                               {
+                                       left: clientScroll.l + ((Math.min(clientScroll.w,clientScroll.iw) - size.wb)/2) + 'px'
+                               }
+                       );
+       }
+});
+if (!$.easing.easeout) {
+       $.easing.easeout = function(p, n, firstNum, delta, duration) {
+               return -delta * ((n=n/duration-1)*n*n*n - 1) + firstNum;
+       };
+}
+       
 })(jQuery);
\ No newline at end of file
index 6edba1a..6789531 100644 (file)
-\r
-var PixasticEditor = (function () {\r
-\r
-       var $frame;     // iframe container element\r
-       var $editor;    // editor container element\r
-\r
-       // various UI structures\r
-       var accordionElements = {};\r
-       var tabElements = {};\r
-       var activeTabId;\r
-       var $activeTabContent;\r
-\r
-       var isRunning = false;\r
-\r
-       var $loadingScreen;\r
-\r
-       var $imageCanvas;       // the canvas holding the current state of the image\r
-       var $displayCanvas;     // the canvas element displayed on the screen, also the working canvas (where preview operations are performed)\r
-       var imageCtx;\r
-\r
-       var imageWidth = 0;     // dimensions of the current image state\r
-       var imageHeight = 0;\r
-\r
-       var undoImages = [];    // canvas elements holding previous image states\r
-       var undoLevels = 10;\r
-\r
-       var doc;\r
-\r
-       var $;\r
-\r
-       // test for valid file formats for toDataURL()\r
-       // we do that by calling it with each of the mime types in testFormats\r
-       // and then doing string checking on the resulting data: URI to see if it succeeded\r
-       var saveFormats = [];\r
-       var testFormats = [["image/jpeg", "JPEG"], ["image/png", "PNG"]];\r
-       var testCanvas = document.createElement("canvas");\r
-       if (testCanvas.toDataURL) {\r
-               testCanvas.width = testCanvas.height = 1;\r
-               for (var i=0;i<testFormats.length;i++) {\r
-                       var data = testCanvas.toDataURL(testFormats[i][0]);\r
-                       if (data.substr(0, 5 + testFormats[i][0].length) == "data:" + testFormats[i][0])\r
-                               saveFormats.push({mime:testFormats[i][0], name:testFormats[i][1]});\r
-               }\r
-       }\r
-\r
-\r
-       // pops up an error dialog with the specified text (errTxt),\r
-       // if no context is provided, the name of the calling function is used.\r
-       // The final message is returned for easy throwing of actual errors\r
-       function errorDialog(errTxt, context) {\r
-               if (!($editor && $editor.get && $editor.get(0)))\r
-                       throw new Error("errorDialog(): $editor doesn't exist");\r
-\r
-               var caller = errorDialog.caller.toString().split(" ")[1];\r
-               caller = caller.substring(0, caller.indexOf("("));\r
-               context = context || caller;\r
-               errTxt = context + "(): " + errTxt;\r
-               var dialog = $j("<div></div>", doc)\r
-                       .addClass("error-dialog")\r
-                       .attr("title", "Oops!")\r
-                       .html(errTxt)\r
-                       .dialog();\r
-               // the dialog is added outside the Pixastic container, so get it back in.\r
-               var dialogParent = $j(dialog.get(0).parentNode);\r
-               dialogParent.appendTo($editor);\r
-\r
-               return errTxt;\r
-       }\r
-       \r
-       function enableTab(id, refresh) {\r
-               if (id == activeTabId && !refresh)\r
-                       return;\r
-\r
-               activeTabId = id;\r
-\r
-               var activeIndex = 0;\r
-\r
-               if ($activeTabContent) {\r
-                       if ($activeTabContent.get(0)) {\r
-                               var $parent = $j($activeTabContent.get(0).parentNode);\r
-                               activeIndex = $parent.data("accordionindex");\r
-                               if ($parent.data("ondeactivate")) {\r
-                                       $parent.data("ondeactivate")();\r
-                               }\r
-                               if ($parent.data("previewCheckbox"))\r
-                                       $parent.data("previewCheckbox").attr("checked", false);\r
-                               $parent.data("uidesc").previewEnabled = false;\r
-                               if ($parent.data("uidesc").forcePreview)\r
-                                       $parent.data("uidesc").previewEnabled = true;\r
-                       }\r
-               }\r
-\r
-\r
-               for (var a in accordionElements) {\r
-                       if (accordionElements.hasOwnProperty(a)) {\r
-                               accordionElements[a].accordion("option", "animated", false);\r
-                               accordionElements[a].accordion("activate", -1);\r
-                               accordionElements[a].hide();\r
-                               tabElements[a].removeClass("active");\r
-\r
-                       }\r
-               }\r
-\r
-               accordionElements[id].accordion("option", "animated", false);\r
-               accordionElements[id].accordion("activate", refresh ? activeIndex : 0);\r
-               tabElements[id].addClass("active");\r
-               accordionElements[id].show();\r
-               accordionElements[id].accordion("option", "animated", "slide");\r
-               resetDisplayCanvas();\r
-       }\r
-\r
-       // revert to a previous image state\r
-       function undo(idx) {\r
-               var undoImage = undoImages[idx];\r
-\r
-               if (!undoImage) \r
-                       throw new Error(errorDialog("Invalid undo state"));\r
-               if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))\r
-                       throw new Error(errorDialog("$imageCanvas doesn't exist"));\r
-\r
-               var canvas = $imageCanvas.get(0);\r
-               addUndo(canvas);\r
-               canvas.width = imageWidth = undoImage.width;\r
-               canvas.height = imageHeight = undoImage.height;\r
-               canvas.getContext("2d").drawImage(undoImage,0,0);\r
-\r
-               enableTab(activeTabId, true);\r
-               resetDisplayCanvas();\r
-       }\r
-\r
-       function addUndo(canvasElement) {\r
-               if (!canvasElement)\r
-                       throw new Error(errorDialog("No undo image state provided"));\r
-\r
-               if (undoImages.length == undoLevels) {\r
-                       undoImages.shift();\r
-               }\r
-               var undoCanvas = document.createElement("canvas");\r
-               undoCanvas.width = canvasElement.width;\r
-               undoCanvas.height = canvasElement.height;\r
-               undoCanvas.getContext("2d").drawImage(canvasElement,0,0);\r
-               $j(undoCanvas).addClass("undo-canvas");\r
-               undoImages.push(undoCanvas);\r
-               updateUndoList();\r
-       }\r
-\r
-       function updateUndoList() {\r
-               var $listCtr = $j("#undo-bar", doc)\r
-                       .html("");\r
-\r
-               var ctrHeight = $listCtr.height();\r
-\r
-               var $testCanvas = $j("<canvas></canvas>", doc)\r
-                       .addClass("undo-canvas-small")\r
-                       .addClass("far-far-away")\r
-                       .appendTo("body");\r
-\r
-               var canvasHeight = $testCanvas.height();\r
-               var canvasWidth = $testCanvas.width();\r
-               var canvasCSSHeight = canvasHeight + parseInt($testCanvas.css("margin-top"),10) + parseInt($testCanvas.css("margin-bottom"),10);\r
-\r
-               $testCanvas.remove();\r
-\r
-               var undoRatio = canvasWidth / canvasHeight;\r
-\r
-               for (var i=undoImages.length-1;i>=0;i--) {\r
-                       (function(){\r
-                               var canvas = document.createElement("canvas");\r
-                               $j(canvas)\r
-                                       .addClass("undo-canvas-small")\r
-                                       .attr("width", canvasWidth)\r
-                                       .attr("height", canvasHeight);\r
-\r
-                               var image = undoImages[i];\r
-                               $j(image).show();\r
-                               \r
-                               var undoWidth, undoHeight;\r
-                               var imageRatio = image.width / image.height;\r
-\r
-                               if (imageRatio > undoRatio) {   // image too wide\r
-                                       undoWidth = canvasWidth;\r
-                                       undoHeight = canvasWidth / imageRatio;\r
-                               } else {\r
-                                       undoWidth = canvasHeight * imageRatio;\r
-                                       undoHeight = canvasHeight;\r
-                               }\r
-\r
-                               var restWidth = canvasWidth - undoWidth;\r
-                               var restHeight = canvasHeight - undoHeight;\r
-\r
-                               canvas.getContext("2d").drawImage(\r
-                                       image,\r
-                                       0,0,image.width,image.height,\r
-                                       restWidth*0.5, restHeight*0.5,\r
-                                       undoWidth, undoHeight\r
-                               );\r
-\r
-\r
-                               $link = $j("<a href='#'></a>", doc)\r
-                                       .addClass("undo-link")\r
-                                       .appendTo($listCtr)\r
-                                       .mouseover(function(){ $j(this).addClass("hover") })\r
-                                       .mouseout(function(){ $j(this).removeClass("hover") });\r
-                               $j(canvas).appendTo($link);\r
-\r
-                               var displayShowing;\r
-                               var undoIndex = i;\r
-                               $link.click(function() {\r
-                                       $j(image).hide();\r
-                                       $j(image).remove();\r
-                                       undo(undoIndex);\r
-                                       if (displayShowing)\r
-                                               $displayCanvas.show();\r
-                                       $j(".jcrop-holder", doc).show();\r
-                               });\r
-\r
-                               $link.mouseover(function() {\r
-                                       displayShowing = $displayCanvas.css("display") != "none";\r
-                                       var $imagectr = $j("#image-container", doc);\r
-\r
-                                       $j(".jcrop-holder", doc).hide();\r
-                                       $displayCanvas.hide();\r
-                                       $j(image).appendTo($imagectr);\r
-\r
-                                       var h1 = $j("#image-area", doc).height();\r
-                                       var h2 = image.height;\r
-                                       var m = Math.max(0, (h1 - h2) / 2);\r
-                                       $imagectr.css("marginTop", m);\r
-                       \r
-                                       $imagectr.height(image.height);\r
-                               });\r
-\r
-                               $link.mouseout(function() {\r
-                                       $j(image).remove();\r
-                                       if (displayShowing)\r
-                                               $displayCanvas.show();\r
-                                       $j(".jcrop-holder", doc).show();\r
-                                       updateDisplayCanvas();\r
-                               });\r
-\r
-\r
-                               $j(canvas).attr("title", "Click to revert to this previous image");\r
-\r
-                       })();\r
-               }\r
-       }\r
-\r
-\r
-       function applyAction(id, options, afteraction) {\r
-               if (!Pixastic.Actions[id])\r
-                       throw new Error("applyAction(): unknown action [" + id + "]");\r
-\r
-               $j("#action-bar-overlay", doc).show();\r
-\r
-               setTimeout(function() {\r
-                       options.leaveDOM = true;\r
-                       var canvasElement = $imageCanvas.get(0);\r
-                       addUndo(canvasElement)\r
-       \r
-                       var res = Pixastic.process(\r
-                               canvasElement, id, options,\r
-                               function(resCanvas) {\r
-                                       canvasElement.width = imageWidth = resCanvas.width;\r
-                                       canvasElement.height = imageHeight = resCanvas.height;\r
-       \r
-                                       var ctx = canvasElement.getContext("2d");\r
-                                       ctx.clearRect(0,0,imageWidth,imageHeight);\r
-                                       ctx.drawImage(resCanvas,0,0);\r
-                                       $imageCanvas = $j(canvasElement);\r
-                                       resetDisplayCanvas();\r
-       \r
-                                       $j("#action-bar-overlay", doc).hide();\r
-\r
-                                       if (afteraction)\r
-                                               afteraction();\r
-                               }\r
-                       );\r
-                       if (!res)\r
-                               throw new Error("applyAction(): Pixastic.process() failed for action [" + id + "]");\r
-               },1);\r
-       }\r
-\r
-\r
-       function previewAction(id, options, afteraction) {\r
-               if (!Pixastic.Actions[id])\r
-                       throw new Error("applyAction(): unknown action [" + id + "]");\r
-\r
-               $j("#action-bar-overlay", doc).show();\r
-\r
-               resetDisplayCanvas();\r
-\r
-               options.leaveDOM = true;\r
-               var canvasElement = $displayCanvas.get(0);\r
-\r
-               var res = Pixastic.process(\r
-                       canvasElement, id, options,\r
-                       function(resCanvas) {\r
-\r
-                               canvasElement.width = resCanvas.width;\r
-                               canvasElement.height = resCanvas.height;\r
-\r
-                               var ctx = canvasElement.getContext("2d");\r
-                               ctx.clearRect(0,0,canvasElement.width,canvasElement.height);\r
-                               ctx.drawImage(resCanvas,0,0);\r
-                               updateDisplayCanvas();\r
-                               updateOverlay();\r
-\r
-                               $j("#action-bar-overlay", doc).hide();\r
-\r
-                               if (afteraction)\r
-                                       afteraction();\r
-                       }\r
-               );\r
-       }\r
-\r
-       var onwindowresize = function() {\r
-               updateDisplayCanvas();\r
-               updateOverlay();\r
-       }\r
-\r
-       var baseUrl = ""\r
-\r
-       function buildEditor() {\r
-               var styles = [\r
-                       "jquery-ui-1.7.1.custom.css",\r
-                       "jquery.Jcrop.css",\r
-                       "pixastic.css"\r
-               ];\r
-\r
-               for (var i=0;i<styles.length;i++) {\r
-                       var s = doc.createElement("link");\r
-                       s.href = baseUrl + styles[i];\r
-                       s.type = "text/css";\r
-                       s.rel = "stylesheet";\r
-                       doc.getElementsByTagName("head")[0].appendChild( s );\r
-               }\r
-\r
-               undoImages = [];\r
-               accordionElements = {};\r
-               tabElements = {};\r
-               activeTabId = -1;\r
-               $activeTabContent = null;\r
-\r
-               // setup DOM UI skeleton\r
-               $editor = $j("<div />", doc)\r
-                       .attr("id", "pixastic-editor")\r
-                       .appendTo($j(doc.body));\r
-\r
-               $editor.append(\r
-                       $j("<div id='background' />", doc),\r
-                       $j("<div id='edit-ctr-1' />", doc).append(\r
-                               $j("<div id='edit-ctr-2' />", doc).append(\r
-                                       $j("<div id='controls-bar' />", doc).append(\r
-                                               $j("<div id='action-bar' />", doc).append(\r
-                                                       $j("<div id='action-bar-overlay' />", doc)\r
-                                               ),\r
-                                               $j("<div id='undo-bar' />", doc)\r
-                                       ),\r
-                                       $j("<div id='image-area' />", doc).append(\r
-                                               $j("<div id='image-area-sub' />", doc).append(\r
-                                                       $j("<div id='image-container' />", doc),\r
-                                                       $j("<div id='image-overlay-container' />", doc).append(\r
-                                                               $j("<div id='image-overlay' />", doc)\r
-                                                       )\r
-                                               )\r
-                                       )\r
-                               )\r
-                       ),\r
-                       $j("<div id='main-bar' />", doc),\r
-                       $j("<div id='powered-by-pixastic'><a href=\"http://www.pixastic.com/\" target=\"_blank\">Powered by Pixastic</a></div>", doc)\r
-               );\r
-\r
-               $j("#image-container", doc).append(\r
-                       $displayCanvas = $j("<canvas />", doc)\r
-                               .addClass("display-canvas")\r
-               );\r
-\r
-               // loop through all  defined UI action controls\r
-               var tabs = PixasticEditor.UI.data.tabs;\r
-\r
-               for (var i=0;i<tabs.length;i++) {\r
-                       (function() {\r
-       \r
-                       var tab = tabs[i];\r
-\r
-                       var $tabElement = $j("<a href=\"#\">" + tab.title + "</a>", doc)\r
-                               .attr("id", "main-tab-button-" + tab.id)\r
-                               .addClass("main-tab")\r
-                               .click(function() {\r
-                                       enableTab(tab.id);\r
-                               })\r
-                               .mouseover(function(){ $j(this).addClass("hover") })\r
-                               .mouseout(function(){ $j(this).removeClass("hover") });\r
-       \r
-                       $j("#main-bar", doc).append($tabElement);\r
-\r
-                       tabElements[tab.id] = $tabElement;\r
-\r
-                       var $menu = $j("<div/>", doc);\r
-                       accordionElements[tab.id] = $menu;\r
-\r
-                       for (var j=0;j<tab.actions.length;j++) {\r
-                               (function() {\r
-\r
-                               var action = tab.actions[j];\r
-\r
-                               var $actionElement = $j("<div><h3><a href=\"#\">" + action.title + "</a></h3></div>", doc)\r
-\r
-                               $menu.append($actionElement);\r
-\r
-                               var $content = $j("<div></div>", doc)\r
-                                       .attr("id", "pixastic-action-tab-content-" + action.id)\r
-                                       .appendTo($actionElement);\r
-\r
-                               var controlOptions = [];\r
-\r
-                               action.previewEnabled = false;\r
-                               if (action.forcePreview)\r
-                                       action.previewEnabled = true;\r
-\r
-                               function togglePreview(enable, doAction) {\r
-                                       if (enable && !action.previewEnabled && doAction)\r
-                                               doAction(true);\r
-                                       if (!enable && action.previewEnabled)\r
-                                               resetDisplayCanvas();\r
-                       \r
-                                       action.previewEnabled = enable;\r
-                               }\r
-\r
-                               var reset = function() {\r
-                                       for (var i in controlOptions) {\r
-                                               if (controlOptions.hasOwnProperty(i)) {\r
-                                                       controlOptions[i].reset();\r
-                                               }\r
-                                       }\r
-                                       if (action.previewEnabled)\r
-                                               doAction(true);\r
-                               }\r
-                               var doAction = function(isPreview) {\r
-                                       var options = {};\r
-                                       for (var i in controlOptions) {\r
-                                               if (controlOptions.hasOwnProperty(i)) {\r
-                                                       options[i] = controlOptions[i].valueField.val();\r
-                                               }\r
-                                       }\r
-\r
-                                       var afteraction = function() {\r
-                                               if (action.onafteraction)\r
-                                                       action.onafteraction(action, isPreview);\r
-                                               if (!isPreview)\r
-                                                       resetDisplayCanvas();\r
-       \r
-                                               if (!isPreview && !action.forcePreview) {\r
-                                                       $j("#pixastic-input-preview-" + action.id, doc).attr("checked", false);\r
-                                                       togglePreview(false);\r
-                                                       reset();\r
-                                               }\r
-                                       }\r
-\r
-                                       if (isPreview) {\r
-                                               previewAction(action.id, options, afteraction);\r
-                                       } else {\r
-                                               applyAction(action.id, options, afteraction);\r
-                                       }\r
-\r
-                               }\r
-\r
-                               var hadInputs = false;\r
-\r
-                               if (action.controls) {\r
-                                       var onChange = function() {};\r
-                                       if (action.isAction && action.preview) {\r
-                                               onChange = function() {\r
-                                                       if (action.previewEnabled)\r
-                                                               doAction(true)\r
-                                               };\r
-                                       }\r
-\r
-                                       for (var k=0;k<action.controls.length;k++) {\r
-                                               var control = action.controls[k];\r
-                                               if (typeof control.defaultValue != "function") {\r
-                                                       (function(){\r
-                                                       var defVal = control.defaultValue;\r
-                                                       control.defaultValue = function() {\r
-                                                               return defVal;\r
-                                                       }\r
-                                                       })();\r
-                                               }\r
-                                               var controlId = action.id + "-" + control.option;\r
-\r
-                                               if (control.type != "output")\r
-                                                       hadInputs = true;\r
-\r
-                                               switch (control.type) {\r
-                                                       case "number" :\r
-                                                               switch (control.ui) {\r
-                                                                       case "slider" : \r
-                                                                               var slider = PixasticEditor.UI.makeSlider(\r
-                                                                                       control.label, controlId, \r
-                                                                                       control.range[0], control.range[1], control.step, control.defaultValue, onChange\r
-                                                                               );\r
-               \r
-                                                                               slider.container.appendTo($content);\r
-                                                                               controlOptions[control.option] = slider;\r
-                                                                               break;\r
-                                                                       case "text" : \r
-                                                                               var text = PixasticEditor.UI.makeNumericInput(\r
-                                                                                       control.label, control.labelRight, controlId, \r
-                                                                                       control.range[0], control.range[1], control.step, control.defaultValue, onChange\r
-                                                                               );\r
-                                                                               text.container.appendTo($content);\r
-                                                                               controlOptions[control.option] = text;\r
-                                                                               break;\r
-                                                               }\r
-                                                               break;\r
-                                                       case "boolean" :\r
-                                                               switch (control.ui) {\r
-                                                                       case "checkbox" : \r
-                                                                               var checkbox = PixasticEditor.UI.makeCheckbox(\r
-                                                                                       control.label, controlId, control.defaultValue, onChange\r
-                                                                               );\r
-               \r
-                                                                               checkbox.container.appendTo($content);\r
-                                                                               controlOptions[control.option] = checkbox;\r
-                                                                               break;\r
-                                                               }\r
-                                                       case "string" :\r
-                                                               switch (control.ui) {\r
-                                                                       case "select" : \r
-                                                                               var select = PixasticEditor.UI.makeSelect(\r
-                                                                                       control.label, controlId, control.values, control.defaultValue, onChange\r
-                                                                               );\r
-               \r
-                                                                               select.container.appendTo($content);\r
-                                                                               controlOptions[control.option] = select;\r
-                                                                               break;\r
-                                                               }\r
-                                                               break;\r
-                                                       case "output" :\r
-                                                               var outputText = $j("<div></div>", doc)\r
-                                                                       .addClass("ui-action-output")\r
-                                                                       .html(control.content)\r
-                                                                       .appendTo($content);\r
-                                                               break;\r
-                                               }\r
-                                       }\r
-                               }\r
-\r
-                               if (action.isAction) {\r
-\r
-                                       var $applyButton = PixasticEditor.UI.makeButton("Apply")\r
-                                               .addClass("pixastic-option-button-apply")\r
-                                               .click(function() {doAction();});\r
-\r
-                                       $content.append($applyButton);\r
-\r
-                                       if (hadInputs) {\r
-                                               var $resetButton = PixasticEditor.UI.makeButton("Reset")\r
-                                                       .addClass("pixastic-option-button-reset")\r
-                                                       .click(reset);\r
-       \r
-                                               $content.append($resetButton)\r
-                                       }\r
-\r
-                                       if (action.preview && !action.forcePreview) {\r
-                                               var $checkctr = $j("<div></div>", doc)\r
-                                                       .addClass("ui-checkbox-container")\r
-                                                       .addClass("ui-preview-checkbox-container");\r
-\r
-                                               var $label = $j("<label></label>", doc)\r
-                                                       .addClass("ui-checkbox-label")\r
-                                                       .attr("for", "pixastic-input-preview-" + action.id)\r
-                                                       .html("Preview:")\r
-                                                       .appendTo($checkctr);\r
-\r
-                                               var $checkbox = $j("<input type=\"checkbox\"></input>", doc)\r
-                                                       .addClass("ui-checkbox")\r
-                                                       .attr("id", "pixastic-input-preview-" + action.id)\r
-                                                       .appendTo($checkctr)\r
-                                                       .change(function() {\r
-                                                               togglePreview(this.checked, doAction)\r
-                                                       });\r
-\r
-                                               $content.append($checkctr);\r
-\r
-                                               $content.data("previewCheckbox", $checkbox);\r
-                                       }\r
-\r
-                               }\r
-\r
-\r
-                               if (typeof action.content == "function") {\r
-                                       action.content($content);\r
-                               }\r
-\r
-                               // stupid hack to make it possible to get $content in change event (below)\r
-                               $j("<span></span>", doc).appendTo($content);\r
-\r
-                               $content.data("controlOptions", controlOptions);\r
-                               $content.data("onactivate", action.onactivate);\r
-                               $content.data("ondeactivate", action.ondeactivate);\r
-                               $content.data("onoverlayupdate", action.onoverlayupdate);\r
-                               $content.data("accordionindex", j);\r
-                               $content.data("uidesc", action);\r
-\r
-                               })();\r
-                       }\r
-       \r
-                       $j("#action-bar", doc).append($menu);\r
-\r
-                       $menu.hide().accordion({\r
-                               header: "h3",\r
-                               autoHeight : false,\r
-                               collapsible : true,\r
-                               active: -1\r
-                       })\r
-                       .bind("accordionchange", \r
-                               function(event, ui) {\r
-                                       resetDisplayCanvas();\r
-\r
-                                       // oldContent / newContent are arrays of whatever elements are present in the content area\r
-                                       // We need the parent element (the one holding the content) but if there is no content, how do we get it?\r
-                                       // fixed above by always appending a <span> but that's ugly and needs to be done in some other way\r
-                                       if (ui.oldContent.get(0)) {\r
-                                               var $parent = $j(ui.oldContent.get(0).parentNode);\r
-                                               if ($parent.data("ondeactivate")) {\r
-                                                       $parent.data("ondeactivate")();\r
-                                               }\r
-                                       }\r
-                                       $activeTabContent = ui.newContent;\r
-\r
-                                       if (ui.newContent.get(0)) {\r
-                                               var $parent = $j(ui.newContent.get(0).parentNode);\r
-                                               if ($parent.data("previewCheckbox"))\r
-                                                       $parent.data("previewCheckbox").attr("checked", false);\r
-                                               $parent.data("uidesc").previewEnabled = false;\r
-                                               if ($parent.data("uidesc").forcePreview)\r
-                                                       $parent.data("uidesc").previewEnabled = true;\r
-\r
-                                               var controlOptions = $parent.data("controlOptions");\r
-                                               for (var i in controlOptions) {\r
-                                                       if (controlOptions.hasOwnProperty(i)) {\r
-                                                               controlOptions[i].reset();\r
-                                                       }\r
-                                               }\r
-                                               if ($parent.data("onactivate")) {\r
-                                                       $parent.data("onactivate")();\r
-                                               }\r
-                                       }\r
-                                       updateDisplayCanvas();\r
-\r
-                               }\r
-                       );\r
-\r
-       \r
-                       })();\r
-               }\r
-\r
-               $j(window).bind("resize", onwindowresize);\r
-       }\r
-\r
-       function showLoadingScreen() {\r
-               if ($loadingScreen) {\r
-                       $loadingScreen.show();\r
-                       return;\r
-               }\r
-               $loadingScreen = $j("<div id=\"loading-screen\" />")\r
-               var $ctr = $j("<div id=\"loading-screen-cell\" />");\r
-               $j("<div />")\r
-                       .addClass("spinner")\r
-                       .appendTo($ctr);\r
-               $loadingScreen.append($ctr);\r
-               $loadingScreen.appendTo("body");\r
-       }\r
-\r
-       function hideLoadingScreen() {\r
-               setTimeout(function() {\r
-                       $loadingScreen.hide();\r
-               }, 1);\r
-       }\r
-\r
-       var oldScrollLeft;\r
-       var oldScrollTop;\r
-       var oldOverflow;\r
-\r
-       // fire it up\r
-       function init(callback) {\r
-               isRunning = true;\r
-\r
-               showLoadingScreen();\r
-\r
-               oldScrollLeft = document.body.scrollLeft;\r
-               oldScrollTop = document.body.scrollTop;\r
-               oldOverflow = document.body.style.overflow;\r
-\r
-               document.body.scrollLeft = 0;\r
-               document.body.scrollTop = 0;\r
-               document.body.style.overflow = "hidden";\r
-\r
-               $frame = $j("<iframe />");\r
-               $frame.hide();\r
-               $frame.css({\r
-                       position : "absolute",\r
-                       left : document.body.scrollLeft + "px",\r
-                       top : document.body.scrollTop + "px",\r
-                       width : "100%",\r
-                       height : "100%",\r
-                       zIndex : "11"\r
-               });\r
-               $frame.load(function(){\r
-                       doc = $frame.get(0).contentDocument;\r
-\r
-                       buildEditor();\r
-                       callback();\r
-                       $frame.show();\r
-                       hideLoadingScreen();\r
-                       setTimeout(function(){\r
-                               updateDisplayCanvas();\r
-                       },10);\r
-               });\r
-               $frame.appendTo("body");\r
-       }\r
-\r
-       // unload the editor, remove all elements added to the page and restore whatever properties we messed with\r
-       function unload() {\r
-               $j(window).unbind("resize", onwindowresize);\r
-               $frame.hide();\r
-               $editor.hide();\r
-               $editor.remove();\r
-               $frame.remove();\r
-\r
-               document.body.scrollLeft = oldScrollLeft;\r
-               document.body.scrollTop = oldScrollTop;\r
-               document.body.style.overflow = oldOverflow;\r
-\r
-               isRunning = false;\r
-       }\r
-\r
-\r
-       // resets the display canvas (clears the canvas and repaints the current state)\r
-       // then updates display and overlay\r
-       function resetDisplayCanvas() {\r
-               if (!($displayCanvas && $displayCanvas.get))    throw new Error(errorDialog("$displayCanvas doesn't exist"));\r
-               if (!($imageCanvas && $imageCanvas.get))        throw new Error(errorDialog("$imageCanvas doesn't exist"));\r
-\r
-               var display = $displayCanvas.get(0);\r
-               var image = $imageCanvas.get(0);\r
-\r
-               if (!display)   throw new Error(errorDialog("resetDisplayCanvas(): No elements in $displayCanvas"));\r
-               if (!image)     throw new Error(errorDialog("resetDisplayCanvas(): No elements in $imageCanvas"));\r
-\r
-               display.width = imageWidth;\r
-               display.height = imageHeight;\r
-               display.getContext("2d").drawImage( image, 0, 0 );\r
-\r
-               updateDisplayCanvas();\r
-               updateOverlay();\r
-       }\r
-\r
-       // updates the display by resetting the height and margin of the image container\r
-       // this is mainly to keep vertical centering\r
-       function updateDisplayCanvas() {\r
-               var $imageCtr = $j("#image-container", doc);\r
-               var $editArea = $j("#image-area", doc);\r
-\r
-               if (!$imageCtr.get(0))          throw new Error(errorDialog("updateDisplayCanvas(): $imageCtr doesn't exist"));\r
-               if (!$displayCanvas.get(0))     throw new Error(errorDialog("updateDisplayCanvas(): $displayCanvas doesn't exist"));\r
-               if (!$editArea.get(0))          throw new Error(errorDialog("updateDisplayCanvas(): $editArea doesn't exist"));\r
-\r
-               var h2 = $displayCanvas.get(0).height;\r
-               var h1 = $j("#image-area", doc).height();\r
-               var m = Math.max(0, (h1 - h2) / 2);\r
-               $imageCtr.height(h2);\r
-               $imageCtr.css("marginTop", m);\r
-       }\r
-\r
-       // basically the same as updateDisplayCanvas but for the image overlay\r
-       function updateOverlay() {\r
-               var $overlay = $j("#image-overlay-container", doc);\r
-               var $imagectr = $j("#image-container", doc);\r
-               $overlay.height($imagectr.height());\r
-               $overlay.css("marginTop", $imagectr.css("marginTop"));\r
-\r
-               if ($activeTabContent && $activeTabContent.get(0)) {\r
-                       var $tabContent = $j($activeTabContent.get(0).parentNode);\r
-                       if (typeof $tabContent.data("onoverlayupdate") == "function")\r
-                               $tabContent.data("onoverlayupdate")();\r
-               }\r
-       }\r
-\r
-       var imageIsLoading = false;\r
-       var originalImageElement;\r
-       var $tmpImg;\r
-\r
-       function loadImage(imgEl) {\r
-               if (imageIsLoading) \r
-                       return;\r
-\r
-               imageIsLoading = true;\r
-\r
-               originalImageElement = imgEl;\r
-\r
-               $imageCanvas = $j("<canvas />", doc);\r
-               imageCtx = $imageCanvas.get(0).getContext("2d");\r
-\r
-               imageWidth = 0;\r
-               imageHeight = 0;\r
-               $imageCanvas.attr("width", 0);\r
-               $imageCanvas.attr("height", 0);\r
-\r
-               if (imgEl.tagName.toLowerCase() == "img" && !imgEl._pixasticCanvas) {\r
-                       var onload = function(el) {\r
-                               imageWidth = el.offsetWidth;\r
-                               imageHeight = el.offsetHeight;\r
-                               $imageCanvas.attr("width", imageWidth);\r
-                               $imageCanvas.attr("height", imageHeight);\r
-                               imageCtx.drawImage(el,0,0);\r
-                               $tmpImg.remove();\r
-                               imageIsLoading = false;\r
-                               enableTab("reshape");\r
-                               setTimeout(function() {\r
-                                       resetDisplayCanvas();\r
-                               }, 10);\r
-                       }\r
-                       $tmpImg = $j("<img />", doc)\r
-                               .css("position", "absolute")\r
-                               .css("left", "-9999px")\r
-                               .css("top", "-9999px")\r
-                               .appendTo("body")\r
-                               .load(function(){onload(this);})\r
-                               .error(function(){\r
-                                       throw new Error("Could not load temporary copy image. Is provided image valid?");\r
-                                       unload();\r
-                               })\r
-                               .attr("src", imgEl.src);\r
-                               if ($tmpImg.attr("complete")) {\r
-                                       onload($tmpImg.get(0));\r
-                               }\r
-               } else {\r
-                       var $canvas = imgEl._pixasticCanvas || imgEl;\r
-                       imageWidth = $canvas.attr("width");\r
-                       imageHeight = $canvas.attr("height");\r
-                       $imageCanvas.attr("width", imageWidth);\r
-                       $imageCanvas.attr("height", imageHeight);\r
-                       imageCtx.drawImage($canvas.get(0), 0, 0);\r
-                       imageIsLoading = false;\r
-                       enableTab("reshape");\r
-                       resetDisplayCanvas();\r
-               }\r
-       }\r
-\r
-       // return public interface\r
-       return {\r
-               /*\r
-               // don't call. For now we must load the image immediately via load()\r
-               loadImage : function(imgEl) {\r
-                       if (!isRunning) return false;\r
-                       loadImage(imgEl);\r
-               },\r
-               */\r
-               saveToPage : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::saveToPage(): Editor is not running");\r
-\r
-                       var $canvas = PixasticEditor.getImageCanvas();\r
-                       var img = PixasticEditor.getOriginalImage();\r
-                       if (img.tagName.toLowerCase() == "canvas") {\r
-                               img.width = $canvas.attr("width");\r
-                               img.height = $canvas.attr("height");\r
-                               img.getContext("2d").drawImage($canvas.get(0), 0, 0);\r
-                       } else {\r
-                               img.src = PixasticEditor.getDataURI();\r
-                       }\r
-                       img._pixasticCanvas = PixasticEditor.getImageCanvas();\r
-               },\r
-               load : function(img, customBaseUrl) {\r
-                       if (isRunning) return false;\r
-\r
-                       if (!img)\r
-                               throw new Error("Must be called with an image or canvas as its first argument", "PixasticEditor::load")\r
-\r
-                       $ = PixasticEditor.jQuery;\r
-\r
-                       baseUrl = customBaseUrl || "http://www.pixastic.com/editor-test/";\r
-\r
-                       init(function() {\r
-                               if (img && img.tagName.toLowerCase() == "img" || img.tagName.toLowerCase() == "canvas") {\r
-                                       loadImage(img);\r
-                               }\r
-                       });\r
-               },\r
-\r
-               unload : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::unload(): Editor is not running");\r
-                       unload();\r
-               },\r
-\r
-               getDocument : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getDocument(): Editor is not running");\r
-\r
-                       return doc;\r
-               },\r
-\r
-               validSaveFormats : function() {\r
-                       return saveFormats;\r
-               },\r
-\r
-               getOriginalImage : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getOriginalImage(): Editor is not running");\r
-                       return originalImageElement;\r
-               },\r
-\r
-               getDataURI : function(mime) {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getDataURI(): Editor is not running");\r
-\r
-                       if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))\r
-                               throw new Error(errorDialog("$imageCanvas doesn't exist", "getImageCanvas"));\r
-\r
-                       return $imageCanvas.get(0).toDataURL(mime||"image/png");\r
-               },\r
-\r
-               getImageCanvas : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getImageCanvas(): Editor is not running");\r
-\r
-                       if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))\r
-                               throw new Error(errorDialog("$imageCanvas doesn't exist", "getImageCanvas"));\r
-\r
-                       return $imageCanvas;\r
-               },\r
-               getOverlay : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getOverlay(): Editor is not running");\r
-\r
-                       return $j("#image-overlay", doc);\r
-               },\r
-               getDisplayCanvas : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getDisplayCanvas(): Editor is not running");\r
-\r
-                       if (!($displayCanvas && $displayCanvas.get && $displayCanvas.get(0)))\r
-                               throw new Error(errorDialog("$displayCanvas doesn't exist", "getDisplayCanvas"));\r
-                       return $displayCanvas;\r
-               },\r
-               getDisplayWidth : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getDisplayWidth(): Editor is not running");\r
-\r
-                       return displayWidth;\r
-               },\r
-               getDisplayHeight : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getDisplayHeight(): Editor is not running");\r
-\r
-                       return displayHeight;\r
-               },\r
-               getImageWidth : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getImageWidth(): Editor is not running");\r
-\r
-                       return imageWidth;\r
-               },\r
-               getImageHeight : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getImageHeight(): Editor is not running");\r
-\r
-                       return imageHeight;\r
-               },\r
-               errorDialog : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::errorDialog(): Editor is not running");\r
-\r
-                       return errorDialog.apply(null, arguments);\r
-               }\r
-       }\r
-\r
+
+var PixasticEditor = (function () {
+
+       var $frame;     // iframe container element
+       var $editor;    // editor container element
+
+       // various UI structures
+       var accordionElements = {};
+       var tabElements = {};
+       var activeTabId;
+       var $activeTabContent;
+
+       var isRunning = false;
+
+       var $loadingScreen;
+
+       var $imageCanvas;       // the canvas holding the current state of the image
+       var $displayCanvas;     // the canvas element displayed on the screen, also the working canvas (where preview operations are performed)
+       var imageCtx;
+
+       var imageWidth = 0;     // dimensions of the current image state
+       var imageHeight = 0;
+
+       var undoImages = [];    // canvas elements holding previous image states
+       var undoLevels = 10;
+
+       var doc;
+
+       var $;
+
+       // test for valid file formats for toDataURL()
+       // we do that by calling it with each of the mime types in testFormats
+       // and then doing string checking on the resulting data: URI to see if it succeeded
+       var saveFormats = [];
+       var testFormats = [["image/jpeg", "JPEG"], ["image/png", "PNG"]];
+       var testCanvas = document.createElement("canvas");
+       if (testCanvas.toDataURL) {
+               testCanvas.width = testCanvas.height = 1;
+               for (var i=0;i<testFormats.length;i++) {
+                       var data = testCanvas.toDataURL(testFormats[i][0]);
+                       if (data.substr(0, 5 + testFormats[i][0].length) == "data:" + testFormats[i][0])
+                               saveFormats.push({mime:testFormats[i][0], name:testFormats[i][1]});
+               }
+       }
+
+
+       // pops up an error dialog with the specified text (errTxt),
+       // if no context is provided, the name of the calling function is used.
+       // The final message is returned for easy throwing of actual errors
+       function errorDialog(errTxt, context) {
+               if (!($editor && $editor.get && $editor.get(0)))
+                       throw new Error("errorDialog(): $editor doesn't exist");
+
+               var caller = errorDialog.caller.toString().split(" ")[1];
+               caller = caller.substring(0, caller.indexOf("("));
+               context = context || caller;
+               errTxt = context + "(): " + errTxt;
+               var dialog = $j("<div></div>", doc)
+                       .addClass("error-dialog")
+                       .attr("title", "Oops!")
+                       .html(errTxt)
+                       .dialog();
+               // the dialog is added outside the Pixastic container, so get it back in.
+               var dialogParent = $j(dialog.get(0).parentNode);
+               dialogParent.appendTo($editor);
+
+               return errTxt;
+       }
+       
+       function enableTab(id, refresh) {
+               if (id == activeTabId && !refresh)
+                       return;
+
+               activeTabId = id;
+
+               var activeIndex = 0;
+
+               if ($activeTabContent) {
+                       if ($activeTabContent.get(0)) {
+                               var $parent = $j($activeTabContent.get(0).parentNode);
+                               activeIndex = $parent.data("accordionindex");
+                               if ($parent.data("ondeactivate")) {
+                                       $parent.data("ondeactivate")();
+                               }
+                               if ($parent.data("previewCheckbox"))
+                                       $parent.data("previewCheckbox").attr("checked", false);
+                               $parent.data("uidesc").previewEnabled = false;
+                               if ($parent.data("uidesc").forcePreview)
+                                       $parent.data("uidesc").previewEnabled = true;
+                       }
+               }
+
+
+               for (var a in accordionElements) {
+                       if (accordionElements.hasOwnProperty(a)) {
+                               accordionElements[a].accordion("option", "animated", false);
+                               accordionElements[a].accordion("activate", -1);
+                               accordionElements[a].hide();
+                               tabElements[a].removeClass("active");
+
+                       }
+               }
+
+               accordionElements[id].accordion("option", "animated", false);
+               accordionElements[id].accordion("activate", refresh ? activeIndex : 0);
+               tabElements[id].addClass("active");
+               accordionElements[id].show();
+               accordionElements[id].accordion("option", "animated", "slide");
+               resetDisplayCanvas();
+       }
+
+       // revert to a previous image state
+       function undo(idx) {
+               var undoImage = undoImages[idx];
+
+               if (!undoImage) 
+                       throw new Error(errorDialog("Invalid undo state"));
+               if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))
+                       throw new Error(errorDialog("$imageCanvas doesn't exist"));
+
+               var canvas = $imageCanvas.get(0);
+               addUndo(canvas);
+               canvas.width = imageWidth = undoImage.width;
+               canvas.height = imageHeight = undoImage.height;
+               canvas.getContext("2d").drawImage(undoImage,0,0);
+
+               enableTab(activeTabId, true);
+               resetDisplayCanvas();
+       }
+
+       function addUndo(canvasElement) {
+               if (!canvasElement)
+                       throw new Error(errorDialog("No undo image state provided"));
+
+               if (undoImages.length == undoLevels) {
+                       undoImages.shift();
+               }
+               var undoCanvas = document.createElement("canvas");
+               undoCanvas.width = canvasElement.width;
+               undoCanvas.height = canvasElement.height;
+               undoCanvas.getContext("2d").drawImage(canvasElement,0,0);
+               $j(undoCanvas).addClass("undo-canvas");
+               undoImages.push(undoCanvas);
+               updateUndoList();
+       }
+
+       function updateUndoList() {
+               var $listCtr = $j("#undo-bar", doc)
+                       .html("");
+
+               var ctrHeight = $listCtr.height();
+
+               var $testCanvas = $j("<canvas></canvas>", doc)
+                       .addClass("undo-canvas-small")
+                       .addClass("far-far-away")
+                       .appendTo("body");
+
+               var canvasHeight = $testCanvas.height();
+               var canvasWidth = $testCanvas.width();
+               var canvasCSSHeight = canvasHeight + parseInt($testCanvas.css("margin-top"),10) + parseInt($testCanvas.css("margin-bottom"),10);
+
+               $testCanvas.remove();
+
+               var undoRatio = canvasWidth / canvasHeight;
+
+               for (var i=undoImages.length-1;i>=0;i--) {
+                       (function(){
+                               var canvas = document.createElement("canvas");
+                               $j(canvas)
+                                       .addClass("undo-canvas-small")
+                                       .attr("width", canvasWidth)
+                                       .attr("height", canvasHeight);
+
+                               var image = undoImages[i];
+                               $j(image).show();
+                               
+                               var undoWidth, undoHeight;
+                               var imageRatio = image.width / image.height;
+
+                               if (imageRatio > undoRatio) {   // image too wide
+                                       undoWidth = canvasWidth;
+                                       undoHeight = canvasWidth / imageRatio;
+                               } else {
+                                       undoWidth = canvasHeight * imageRatio;
+                                       undoHeight = canvasHeight;
+                               }
+
+                               var restWidth = canvasWidth - undoWidth;
+                               var restHeight = canvasHeight - undoHeight;
+
+                               canvas.getContext("2d").drawImage(
+                                       image,
+                                       0,0,image.width,image.height,
+                                       restWidth*0.5, restHeight*0.5,
+                                       undoWidth, undoHeight
+                               );
+
+
+                               $link = $j("<a href='#'></a>", doc)
+                                       .addClass("undo-link")
+                                       .appendTo($listCtr)
+                                       .mouseover(function(){ $j(this).addClass("hover") })
+                                       .mouseout(function(){ $j(this).removeClass("hover") });
+                               $j(canvas).appendTo($link);
+
+                               var displayShowing;
+                               var undoIndex = i;
+                               $link.click(function() {
+                                       $j(image).hide();
+                                       $j(image).remove();
+                                       undo(undoIndex);
+                                       if (displayShowing)
+                                               $displayCanvas.show();
+                                       $j(".jcrop-holder", doc).show();
+                               });
+
+                               $link.mouseover(function() {
+                                       displayShowing = $displayCanvas.css("display") != "none";
+                                       var $imagectr = $j("#image-container", doc);
+
+                                       $j(".jcrop-holder", doc).hide();
+                                       $displayCanvas.hide();
+                                       $j(image).appendTo($imagectr);
+
+                                       var h1 = $j("#image-area", doc).height();
+                                       var h2 = image.height;
+                                       var m = Math.max(0, (h1 - h2) / 2);
+                                       $imagectr.css("marginTop", m);
+                       
+                                       $imagectr.height(image.height);
+                               });
+
+                               $link.mouseout(function() {
+                                       $j(image).remove();
+                                       if (displayShowing)
+                                               $displayCanvas.show();
+                                       $j(".jcrop-holder", doc).show();
+                                       updateDisplayCanvas();
+                               });
+
+
+                               $j(canvas).attr("title", "Click to revert to this previous image");
+
+                       })();
+               }
+       }
+
+
+       function applyAction(id, options, afteraction) {
+               if (!Pixastic.Actions[id])
+                       throw new Error("applyAction(): unknown action [" + id + "]");
+
+               $j("#action-bar-overlay", doc).show();
+
+               setTimeout(function() {
+                       options.leaveDOM = true;
+                       var canvasElement = $imageCanvas.get(0);
+                       addUndo(canvasElement)
+       
+                       var res = Pixastic.process(
+                               canvasElement, id, options,
+                               function(resCanvas) {
+                                       canvasElement.width = imageWidth = resCanvas.width;
+                                       canvasElement.height = imageHeight = resCanvas.height;
+       
+                                       var ctx = canvasElement.getContext("2d");
+                                       ctx.clearRect(0,0,imageWidth,imageHeight);
+                                       ctx.drawImage(resCanvas,0,0);
+                                       $imageCanvas = $j(canvasElement);
+                                       resetDisplayCanvas();
+       
+                                       $j("#action-bar-overlay", doc).hide();
+
+                                       if (afteraction)
+                                               afteraction();
+                               }
+                       );
+                       if (!res)
+                               throw new Error("applyAction(): Pixastic.process() failed for action [" + id + "]");
+               },1);
+       }
+
+
+       function previewAction(id, options, afteraction) {
+               if (!Pixastic.Actions[id])
+                       throw new Error("applyAction(): unknown action [" + id + "]");
+
+               $j("#action-bar-overlay", doc).show();
+
+               resetDisplayCanvas();
+
+               options.leaveDOM = true;
+               var canvasElement = $displayCanvas.get(0);
+
+               var res = Pixastic.process(
+                       canvasElement, id, options,
+                       function(resCanvas) {
+
+                               canvasElement.width = resCanvas.width;
+                               canvasElement.height = resCanvas.height;
+
+                               var ctx = canvasElement.getContext("2d");
+                               ctx.clearRect(0,0,canvasElement.width,canvasElement.height);
+                               ctx.drawImage(resCanvas,0,0);
+                               updateDisplayCanvas();
+                               updateOverlay();
+
+                               $j("#action-bar-overlay", doc).hide();
+
+                               if (afteraction)
+                                       afteraction();
+                       }
+               );
+       }
+
+       var onwindowresize = function() {
+               updateDisplayCanvas();
+               updateOverlay();
+       }
+
+       var baseUrl = ""
+
+       function buildEditor() {
+               var styles = [
+                       "jquery-ui-1.7.1.custom.css",
+                       "jquery.Jcrop.css",
+                       "pixastic.css"
+               ];
+
+               for (var i=0;i<styles.length;i++) {
+                       var s = doc.createElement("link");
+                       s.href = baseUrl + styles[i];
+                       s.type = "text/css";
+                       s.rel = "stylesheet";
+                       doc.getElementsByTagName("head")[0].appendChild( s );
+               }
+
+               undoImages = [];
+               accordionElements = {};
+               tabElements = {};
+               activeTabId = -1;
+               $activeTabContent = null;
+
+               // setup DOM UI skeleton
+               $editor = $j("<div />", doc)
+                       .attr("id", "pixastic-editor")
+                       .appendTo($j(doc.body));
+
+               $editor.append(
+                       $j("<div id='background' />", doc),
+                       $j("<div id='edit-ctr-1' />", doc).append(
+                               $j("<div id='edit-ctr-2' />", doc).append(
+                                       $j("<div id='controls-bar' />", doc).append(
+                                               $j("<div id='action-bar' />", doc).append(
+                                                       $j("<div id='action-bar-overlay' />", doc)
+                                               ),
+                                               $j("<div id='undo-bar' />", doc)
+                                       ),
+                                       $j("<div id='image-area' />", doc).append(
+                                               $j("<div id='image-area-sub' />", doc).append(
+                                                       $j("<div id='image-container' />", doc),
+                                                       $j("<div id='image-overlay-container' />", doc).append(
+                                                               $j("<div id='image-overlay' />", doc)
+                                                       )
+                                               )
+                                       )
+                               )
+                       ),
+                       $j("<div id='main-bar' />", doc),
+                       $j("<div id='powered-by-pixastic'><a href=\"http://www.pixastic.com/\" target=\"_blank\">Powered by Pixastic</a></div>", doc)
+               );
+
+               $j("#image-container", doc).append(
+                       $displayCanvas = $j("<canvas />", doc)
+                               .addClass("display-canvas")
+               );
+
+               // loop through all  defined UI action controls
+               var tabs = PixasticEditor.UI.data.tabs;
+
+               for (var i=0;i<tabs.length;i++) {
+                       (function() {
+       
+                       var tab = tabs[i];
+
+                       var $tabElement = $j("<a href=\"#\">" + tab.title + "</a>", doc)
+                               .attr("id", "main-tab-button-" + tab.id)
+                               .addClass("main-tab")
+                               .click(function() {
+                                       enableTab(tab.id);
+                               })
+                               .mouseover(function(){ $j(this).addClass("hover") })
+                               .mouseout(function(){ $j(this).removeClass("hover") });
+       
+                       $j("#main-bar", doc).append($tabElement);
+
+                       tabElements[tab.id] = $tabElement;
+
+                       var $menu = $j("<div/>", doc);
+                       accordionElements[tab.id] = $menu;
+
+                       for (var j=0;j<tab.actions.length;j++) {
+                               (function() {
+
+                               var action = tab.actions[j];
+
+                               var $actionElement = $j("<div><h3><a href=\"#\">" + action.title + "</a></h3></div>", doc)
+
+                               $menu.append($actionElement);
+
+                               var $content = $j("<div></div>", doc)
+                                       .attr("id", "pixastic-action-tab-content-" + action.id)
+                                       .appendTo($actionElement);
+
+                               var controlOptions = [];
+
+                               action.previewEnabled = false;
+                               if (action.forcePreview)
+                                       action.previewEnabled = true;
+
+                               function togglePreview(enable, doAction) {
+                                       if (enable && !action.previewEnabled && doAction)
+                                               doAction(true);
+                                       if (!enable && action.previewEnabled)
+                                               resetDisplayCanvas();
+                       
+                                       action.previewEnabled = enable;
+                               }
+
+                               var reset = function() {
+                                       for (var i in controlOptions) {
+                                               if (controlOptions.hasOwnProperty(i)) {
+                                                       controlOptions[i].reset();
+                                               }
+                                       }
+                                       if (action.previewEnabled)
+                                               doAction(true);
+                               }
+                               var doAction = function(isPreview) {
+                                       var options = {};
+                                       for (var i in controlOptions) {
+                                               if (controlOptions.hasOwnProperty(i)) {
+                                                       options[i] = controlOptions[i].valueField.val();
+                                               }
+                                       }
+
+                                       var afteraction = function() {
+                                               if (action.onafteraction)
+                                                       action.onafteraction(action, isPreview);
+                                               if (!isPreview)
+                                                       resetDisplayCanvas();
+       
+                                               if (!isPreview && !action.forcePreview) {
+                                                       $j("#pixastic-input-preview-" + action.id, doc).attr("checked", false);
+                                                       togglePreview(false);
+                                                       reset();
+                                               }
+                                       }
+
+                                       if (isPreview) {
+                                               previewAction(action.id, options, afteraction);
+                                       } else {
+                                               applyAction(action.id, options, afteraction);
+                                       }
+
+                               }
+
+                               var hadInputs = false;
+
+                               if (action.controls) {
+                                       var onChange = function() {};
+                                       if (action.isAction && action.preview) {
+                                               onChange = function() {
+                                                       if (action.previewEnabled)
+                                                               doAction(true)
+                                               };
+                                       }
+
+                                       for (var k=0;k<action.controls.length;k++) {
+                                               var control = action.controls[k];
+                                               if (typeof control.defaultValue != "function") {
+                                                       (function(){
+                                                       var defVal = control.defaultValue;
+                                                       control.defaultValue = function() {
+                                                               return defVal;
+                                                       }
+                                                       })();
+                                               }
+                                               var controlId = action.id + "-" + control.option;
+
+                                               if (control.type != "output")
+                                                       hadInputs = true;
+
+                                               switch (control.type) {
+                                                       case "number" :
+                                                               switch (control.ui) {
+                                                                       case "slider" : 
+                                                                               var slider = PixasticEditor.UI.makeSlider(
+                                                                                       control.label, controlId, 
+                                                                                       control.range[0], control.range[1], control.step, control.defaultValue, onChange
+                                                                               );
+               
+                                                                               slider.container.appendTo($content);
+                                                                               controlOptions[control.option] = slider;
+                                                                               break;
+                                                                       case "text" : 
+                                                                               var text = PixasticEditor.UI.makeNumericInput(
+                                                                                       control.label, control.labelRight, controlId, 
+                                                                                       control.range[0], control.range[1], control.step, control.defaultValue, onChange
+                                                                               );
+                                                                               text.container.appendTo($content);
+                                                                               controlOptions[control.option] = text;
+                                                                               break;
+                                                               }
+                                                               break;
+                                                       case "boolean" :
+                                                               switch (control.ui) {
+                                                                       case "checkbox" : 
+                                                                               var checkbox = PixasticEditor.UI.makeCheckbox(
+                                                                                       control.label, controlId, control.defaultValue, onChange
+                                                                               );
+               
+                                                                               checkbox.container.appendTo($content);
+                                                                               controlOptions[control.option] = checkbox;
+                                                                               break;
+                                                               }
+                                                       case "string" :
+                                                               switch (control.ui) {
+                                                                       case "select" : 
+                                                                               var select = PixasticEditor.UI.makeSelect(
+                                                                                       control.label, controlId, control.values, control.defaultValue, onChange
+                                                                               );
+               
+                                                                               select.container.appendTo($content);
+                                                                               controlOptions[control.option] = select;
+                                                                               break;
+                                                               }
+                                                               break;
+                                                       case "output" :
+                                                               var outputText = $j("<div></div>", doc)
+                                                                       .addClass("ui-action-output")
+                                                                       .html(control.content)
+                                                                       .appendTo($content);
+                                                               break;
+                                               }
+                                       }
+                               }
+
+                               if (action.isAction) {
+
+                                       var $applyButton = PixasticEditor.UI.makeButton("Apply")
+                                               .addClass("pixastic-option-button-apply")
+                                               .click(function() {doAction();});
+
+                                       $content.append($applyButton);
+
+                                       if (hadInputs) {
+                                               var $resetButton = PixasticEditor.UI.makeButton("Reset")
+                                                       .addClass("pixastic-option-button-reset")
+                                                       .click(reset);
+       
+                                               $content.append($resetButton)
+                                       }
+
+                                       if (action.preview && !action.forcePreview) {
+                                               var $checkctr = $j("<div></div>", doc)
+                                                       .addClass("ui-checkbox-container")
+                                                       .addClass("ui-preview-checkbox-container");
+
+                                               var $label = $j("<label></label>", doc)
+                                                       .addClass("ui-checkbox-label")
+                                                       .attr("for", "pixastic-input-preview-" + action.id)
+                                                       .html("Preview:")
+                                                       .appendTo($checkctr);
+
+                                               var $checkbox = $j("<input type=\"checkbox\"></input>", doc)
+                                                       .addClass("ui-checkbox")
+                                                       .attr("id", "pixastic-input-preview-" + action.id)
+                                                       .appendTo($checkctr)
+                                                       .change(function() {
+                                                               togglePreview(this.checked, doAction)
+                                                       });
+
+                                               $content.append($checkctr);
+
+                                               $content.data("previewCheckbox", $checkbox);
+                                       }
+
+                               }
+
+
+                               if (typeof action.content == "function") {
+                                       action.content($content);
+                               }
+
+                               // stupid hack to make it possible to get $content in change event (below)
+                               $j("<span></span>", doc).appendTo($content);
+
+                               $content.data("controlOptions", controlOptions);
+                               $content.data("onactivate", action.onactivate);
+                               $content.data("ondeactivate", action.ondeactivate);
+                               $content.data("onoverlayupdate", action.onoverlayupdate);
+                               $content.data("accordionindex", j);
+                               $content.data("uidesc", action);
+
+                               })();
+                       }
+       
+                       $j("#action-bar", doc).append($menu);
+
+                       $menu.hide().accordion({
+                               header: "h3",
+                               autoHeight : false,
+                               collapsible : true,
+                               active: -1
+                       })
+                       .bind("accordionchange", 
+                               function(event, ui) {
+                                       resetDisplayCanvas();
+
+                                       // oldContent / newContent are arrays of whatever elements are present in the content area
+                                       // We need the parent element (the one holding the content) but if there is no content, how do we get it?
+                                       // fixed above by always appending a <span> but that's ugly and needs to be done in some other way
+                                       if (ui.oldContent.get(0)) {
+                                               var $parent = $j(ui.oldContent.get(0).parentNode);
+                                               if ($parent.data("ondeactivate")) {
+                                                       $parent.data("ondeactivate")();
+                                               }
+                                       }
+                                       $activeTabContent = ui.newContent;
+
+                                       if (ui.newContent.get(0)) {
+                                               var $parent = $j(ui.newContent.get(0).parentNode);
+                                               if ($parent.data("previewCheckbox"))
+                                                       $parent.data("previewCheckbox").attr("checked", false);
+                                               $parent.data("uidesc").previewEnabled = false;
+                                               if ($parent.data("uidesc").forcePreview)
+                                                       $parent.data("uidesc").previewEnabled = true;
+
+                                               var controlOptions = $parent.data("controlOptions");
+                                               for (var i in controlOptions) {
+                                                       if (controlOptions.hasOwnProperty(i)) {
+                                                               controlOptions[i].reset();
+                                                       }
+                                               }
+                                               if ($parent.data("onactivate")) {
+                                                       $parent.data("onactivate")();
+                                               }
+                                       }
+                                       updateDisplayCanvas();
+
+                               }
+                       );
+
+       
+                       })();
+               }
+
+               $j(window).bind("resize", onwindowresize);
+       }
+
+       function showLoadingScreen() {
+               if ($loadingScreen) {
+                       $loadingScreen.show();
+                       return;
+               }
+               $loadingScreen = $j("<div id=\"loading-screen\" />")
+               var $ctr = $j("<div id=\"loading-screen-cell\" />");
+               $j("<div />")
+                       .addClass("spinner")
+                       .appendTo($ctr);
+               $loadingScreen.append($ctr);
+               $loadingScreen.appendTo("body");
+       }
+
+       function hideLoadingScreen() {
+               setTimeout(function() {
+                       $loadingScreen.hide();
+               }, 1);
+       }
+
+       var oldScrollLeft;
+       var oldScrollTop;
+       var oldOverflow;
+
+       // fire it up
+       function init(callback) {
+               isRunning = true;
+
+               showLoadingScreen();
+
+               oldScrollLeft = document.body.scrollLeft;
+               oldScrollTop = document.body.scrollTop;
+               oldOverflow = document.body.style.overflow;
+
+               document.body.scrollLeft = 0;
+               document.body.scrollTop = 0;
+               document.body.style.overflow = "hidden";
+
+               $frame = $j("<iframe />");
+               $frame.hide();
+               $frame.css({
+                       position : "absolute",
+                       left : document.body.scrollLeft + "px",
+                       top : document.body.scrollTop + "px",
+                       width : "100%",
+                       height : "100%",
+                       zIndex : "11"
+               });
+               $frame.load(function(){
+                       doc = $frame.get(0).contentDocument;
+
+                       buildEditor();
+                       callback();
+                       $frame.show();
+                       hideLoadingScreen();
+                       setTimeout(function(){
+                               updateDisplayCanvas();
+                       },10);
+               });
+               $frame.appendTo("body");
+       }
+
+       // unload the editor, remove all elements added to the page and restore whatever properties we messed with
+       function unload() {
+               $j(window).unbind("resize", onwindowresize);
+               $frame.hide();
+               $editor.hide();
+               $editor.remove();
+               $frame.remove();
+
+               document.body.scrollLeft = oldScrollLeft;
+               document.body.scrollTop = oldScrollTop;
+               document.body.style.overflow = oldOverflow;
+
+               isRunning = false;
+       }
+
+
+       // resets the display canvas (clears the canvas and repaints the current state)
+       // then updates display and overlay
+       function resetDisplayCanvas() {
+               if (!($displayCanvas && $displayCanvas.get))    throw new Error(errorDialog("$displayCanvas doesn't exist"));
+               if (!($imageCanvas && $imageCanvas.get))        throw new Error(errorDialog("$imageCanvas doesn't exist"));
+
+               var display = $displayCanvas.get(0);
+               var image = $imageCanvas.get(0);
+
+               if (!display)   throw new Error(errorDialog("resetDisplayCanvas(): No elements in $displayCanvas"));
+               if (!image)     throw new Error(errorDialog("resetDisplayCanvas(): No elements in $imageCanvas"));
+
+               display.width = imageWidth;
+               display.height = imageHeight;
+               display.getContext("2d").drawImage( image, 0, 0 );
+
+               updateDisplayCanvas();
+               updateOverlay();
+       }
+
+       // updates the display by resetting the height and margin of the image container
+       // this is mainly to keep vertical centering
+       function updateDisplayCanvas() {
+               var $imageCtr = $j("#image-container", doc);
+               var $editArea = $j("#image-area", doc);
+
+               if (!$imageCtr.get(0))          throw new Error(errorDialog("updateDisplayCanvas(): $imageCtr doesn't exist"));
+               if (!$displayCanvas.get(0))     throw new Error(errorDialog("updateDisplayCanvas(): $displayCanvas doesn't exist"));
+               if (!$editArea.get(0))          throw new Error(errorDialog("updateDisplayCanvas(): $editArea doesn't exist"));
+
+               var h2 = $displayCanvas.get(0).height;
+               var h1 = $j("#image-area", doc).height();
+               var m = Math.max(0, (h1 - h2) / 2);
+               $imageCtr.height(h2);
+               $imageCtr.css("marginTop", m);
+       }
+
+       // basically the same as updateDisplayCanvas but for the image overlay
+       function updateOverlay() {
+               var $overlay = $j("#image-overlay-container", doc);
+               var $imagectr = $j("#image-container", doc);
+               $overlay.height($imagectr.height());
+               $overlay.css("marginTop", $imagectr.css("marginTop"));
+
+               if ($activeTabContent && $activeTabContent.get(0)) {
+                       var $tabContent = $j($activeTabContent.get(0).parentNode);
+                       if (typeof $tabContent.data("onoverlayupdate") == "function")
+                               $tabContent.data("onoverlayupdate")();
+               }
+       }
+
+       var imageIsLoading = false;
+       var originalImageElement;
+       var $tmpImg;
+
+       function loadImage(imgEl) {
+               if (imageIsLoading) 
+                       return;
+
+               imageIsLoading = true;
+
+               originalImageElement = imgEl;
+
+               $imageCanvas = $j("<canvas />", doc);
+               imageCtx = $imageCanvas.get(0).getContext("2d");
+
+               imageWidth = 0;
+               imageHeight = 0;
+               $imageCanvas.attr("width", 0);
+               $imageCanvas.attr("height", 0);
+
+               if (imgEl.tagName.toLowerCase() == "img" && !imgEl._pixasticCanvas) {
+                       var onload = function(el) {
+                               imageWidth = el.offsetWidth;
+                               imageHeight = el.offsetHeight;
+                               $imageCanvas.attr("width", imageWidth);
+                               $imageCanvas.attr("height", imageHeight);
+                               imageCtx.drawImage(el,0,0);
+                               $tmpImg.remove();
+                               imageIsLoading = false;
+                               enableTab("reshape");
+                               setTimeout(function() {
+                                       resetDisplayCanvas();
+                               }, 10);
+                       }
+                       $tmpImg = $j("<img />", doc)
+                               .css("position", "absolute")
+                               .css("left", "-9999px")
+                               .css("top", "-9999px")
+                               .appendTo("body")
+                               .load(function(){onload(this);})
+                               .error(function(){
+                                       throw new Error("Could not load temporary copy image. Is provided image valid?");
+                                       unload();
+                               })
+                               .attr("src", imgEl.src);
+                               if ($tmpImg.attr("complete")) {
+                                       onload($tmpImg.get(0));
+                               }
+               } else {
+                       var $canvas = imgEl._pixasticCanvas || imgEl;
+                       imageWidth = $canvas.attr("width");
+                       imageHeight = $canvas.attr("height");
+                       $imageCanvas.attr("width", imageWidth);
+                       $imageCanvas.attr("height", imageHeight);
+                       imageCtx.drawImage($canvas.get(0), 0, 0);
+                       imageIsLoading = false;
+                       enableTab("reshape");
+                       resetDisplayCanvas();
+               }
+       }
+
+       // return public interface
+       return {
+               /*
+               // don't call. For now we must load the image immediately via load()
+               loadImage : function(imgEl) {
+                       if (!isRunning) return false;
+                       loadImage(imgEl);
+               },
+               */
+               saveToPage : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::saveToPage(): Editor is not running");
+
+                       var $canvas = PixasticEditor.getImageCanvas();
+                       var img = PixasticEditor.getOriginalImage();
+                       if (img.tagName.toLowerCase() == "canvas") {
+                               img.width = $canvas.attr("width");
+                               img.height = $canvas.attr("height");
+                               img.getContext("2d").drawImage($canvas.get(0), 0, 0);
+                       } else {
+                               img.src = PixasticEditor.getDataURI();
+                       }
+                       img._pixasticCanvas = PixasticEditor.getImageCanvas();
+               },
+               load : function(img, customBaseUrl) {
+                       if (isRunning) return false;
+
+                       if (!img)
+                               throw new Error("Must be called with an image or canvas as its first argument", "PixasticEditor::load")
+
+                       $ = PixasticEditor.jQuery;
+
+                       baseUrl = customBaseUrl || "http://www.pixastic.com/editor-test/";
+
+                       init(function() {
+                               if (img && img.tagName.toLowerCase() == "img" || img.tagName.toLowerCase() == "canvas") {
+                                       loadImage(img);
+                               }
+                       });
+               },
+
+               unload : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::unload(): Editor is not running");
+                       unload();
+               },
+
+               getDocument : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getDocument(): Editor is not running");
+
+                       return doc;
+               },
+
+               validSaveFormats : function() {
+                       return saveFormats;
+               },
+
+               getOriginalImage : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getOriginalImage(): Editor is not running");
+                       return originalImageElement;
+               },
+
+               getDataURI : function(mime) {
+                       if (!isRunning) throw new Error("PixasticEditor::getDataURI(): Editor is not running");
+
+                       if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))
+                               throw new Error(errorDialog("$imageCanvas doesn't exist", "getImageCanvas"));
+
+                       return $imageCanvas.get(0).toDataURL(mime||"image/png");
+               },
+
+               getImageCanvas : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getImageCanvas(): Editor is not running");
+
+                       if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))
+                               throw new Error(errorDialog("$imageCanvas doesn't exist", "getImageCanvas"));
+
+                       return $imageCanvas;
+               },
+               getOverlay : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getOverlay(): Editor is not running");
+
+                       return $j("#image-overlay", doc);
+               },
+               getDisplayCanvas : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getDisplayCanvas(): Editor is not running");
+
+                       if (!($displayCanvas && $displayCanvas.get && $displayCanvas.get(0)))
+                               throw new Error(errorDialog("$displayCanvas doesn't exist", "getDisplayCanvas"));
+                       return $displayCanvas;
+               },
+               getDisplayWidth : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getDisplayWidth(): Editor is not running");
+
+                       return displayWidth;
+               },
+               getDisplayHeight : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getDisplayHeight(): Editor is not running");
+
+                       return displayHeight;
+               },
+               getImageWidth : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getImageWidth(): Editor is not running");
+
+                       return imageWidth;
+               },
+               getImageHeight : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getImageHeight(): Editor is not running");
+
+                       return imageHeight;
+               },
+               errorDialog : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::errorDialog(): Editor is not running");
+
+                       return errorDialog.apply(null, arguments);
+               }
+       }
+
 })();
\ No newline at end of file
index fa38d04..bee153a 100644 (file)
-/*\r
- * Pixastic Lib - Core Functions - v0.1.3\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-var Pixastic = (function() {\r
-\r
-\r
-       function addEvent(el, event, handler) {\r
-               if (el.addEventListener)\r
-                       el.addEventListener(event, handler, false); \r
-               else if (el.attachEvent)\r
-                       el.attachEvent("on" + event, handler); \r
-       }\r
-\r
-       function onready(handler) {\r
-               var handlerDone = false;\r
-               var execHandler = function() {\r
-                       if (!handlerDone) {\r
-                               handlerDone = true;\r
-                               handler();\r
-                       }\r
-               }\r
-               document.write("<"+"script defer src=\"//:\" id=\"__onload_ie_sumbox__\"></"+"script>");\r
-               var script = document.getElementById("__onload_ie_sumbox__");\r
-               script.onreadystatechange = function() {\r
-                       if (script.readyState == "complete") {\r
-                               script.parentNode.removeChild(script);\r
-                               execHandler();\r
-                       }\r
-               }\r
-               if (document.addEventListener)\r
-                       document.addEventListener("DOMContentLoaded", execHandler, false); \r
-               addEvent(window, "load", execHandler);\r
-       }\r
-\r
-       function init() {\r
-               if (!Pixastic.parseOnLoad) return;\r
-               var imgEls = getElementsByClass("pixastic", null, "img");\r
-               var canvasEls = getElementsByClass("pixastic", null, "canvas");\r
-               var elements = imgEls.concat(canvasEls);\r
-               for (var i=0;i<elements.length;i++) {\r
-                       (function() {\r
-\r
-                       var el = elements[i];\r
-                       var actions = [];\r
-                       var classes = el.className.split(" ");\r
-                       for (var c=0;c<classes.length;c++) {\r
-                               var cls = classes[c];\r
-                               if (cls.substring(0,9) == "pixastic-") {\r
-                                       var actionName = cls.substring(9);\r
-                                       if (actionName != "")\r
-                                               actions.push(actionName);\r
-                               }\r
-                       }\r
-                       if (actions.length) {\r
-                               if (el.tagName.toLowerCase() == "img") {\r
-                                       var dataImg = new Image();\r
-                                       dataImg.src = el.src;\r
-                                       if (dataImg.complete) {\r
-                                               for (var a=0;a<actions.length;a++) {\r
-                                                       var res = Pixastic.applyAction(el, el, actions[a], null);\r
-                                                       if (res) \r
-                                                               el = res;\r
-                                               }\r
-                                       } else {\r
-                                               dataImg.onload = function() {\r
-                                                       for (var a=0;a<actions.length;a++) {\r
-                                                               var res = Pixastic.applyAction(el, el, actions[a], null)\r
-                                                               if (res) \r
-                                                                       el = res;\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                               } else {\r
-                                       setTimeout(function() {\r
-                                               for (var a=0;a<actions.length;a++) {\r
-                                                       var res = Pixastic.applyAction(\r
-                                                               el, el, actions[a], null\r
-                                                       );\r
-                                                       if (res) \r
-                                                               el = res;\r
-                                               }\r
-                                       },1);\r
-                               }\r
-                       }\r
-\r
-                       })();\r
-               }\r
-       }\r
-\r
-//     if (typeof pixastic_no_onready == "undefined") // yuck.\r
-//             onready(init);\r
-\r
-       // getElementsByClass by Dustin Diaz, http://www.dustindiaz.com/getelementsbyclass/\r
-       function getElementsByClass(searchClass,node,tag) {\r
-               var classElements = new Array();\r
-               if ( node == null )\r
-                       node = document;\r
-               if ( tag == null )\r
-                       tag = '*';\r
-\r
-               var els = node.getElementsByTagName(tag);\r
-               var elsLen = els.length;\r
-               var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");\r
-               for (i = 0, j = 0; i < elsLen; i++) {\r
-                       if ( pattern.test(els[i].className) ) {\r
-                               classElements[j] = els[i];\r
-                               j++;\r
-                       }\r
-               }\r
-               return classElements;\r
-       }\r
-\r
-       var debugElement;\r
-\r
-       function writeDebug(text, level) {\r
-               if (!Pixastic.debug) return;\r
-               try {\r
-                       switch (level) {\r
-                               case "warn" : \r
-                                       console.warn("Pixastic:", text);\r
-                                       break;\r
-                               case "error" :\r
-                                       console.error("Pixastic:", text);\r
-                                       break;\r
-                               default:\r
-                                       console.log("Pixastic:", text);\r
-                       }\r
-               } catch(e) {\r
-               }\r
-               if (!debugElement) {\r
-                       \r
-               }\r
-       }\r
-\r
-\r
-       return {\r
-\r
-               parseOnLoad : false,\r
-\r
-               debug : false,\r
-               \r
-               applyAction : function(img, dataImg, actionName, options) {\r
-\r
-                       options = options || {};\r
-\r
-                       var imageIsCanvas = (img.tagName.toLowerCase() == "canvas");\r
-                       if (imageIsCanvas && Pixastic.Client.isIE()) {\r
-                               if (Pixastic.debug) writeDebug("Tried to process a canvas element but browser is IE.");\r
-                               return false;\r
-                       }\r
-\r
-                       var canvas, ctx;\r
-                       if (Pixastic.Client.hasCanvas()) {\r
-                               canvas = document.createElement("canvas");\r
-                               ctx = canvas.getContext("2d");\r
-                       }\r
-\r
-                       var w = parseInt(img.offsetWidth);\r
-                       var h = parseInt(img.offsetHeight);\r
-\r
-                       if (imageIsCanvas) {\r
-                               w = img.width;\r
-                               h = img.height;\r
-                       }\r
-\r
-                       if (actionName.indexOf("(") > -1) {\r
-                               var tmp = actionName;\r
-                               actionName = tmp.substr(0, tmp.indexOf("("));\r
-                               var arg = tmp.match(/\((.*?)\)/);\r
-                               if (arg[1]) {\r
-                                       arg = arg[1].split(";");\r
-                                       for (var a=0;a<arg.length;a++) {\r
-                                               thisArg = arg[a].split("=");\r
-                                               if (thisArg.length == 2) {\r
-                                                       if (thisArg[0] == "rect") {\r
-                                                               var rectVal = thisArg[1].split(",");\r
-                                                               options[thisArg[0]] = {\r
-                                                                       left : parseInt(rectVal[0],10)||0,\r
-                                                                       top : parseInt(rectVal[1],10)||0,\r
-                                                                       width : parseInt(rectVal[2],10)||0,\r
-                                                                       height : parseInt(rectVal[3],10)||0\r
-                                                               }\r
-                                                       } else {\r
-                                                               options[thisArg[0]] = thisArg[1];\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-\r
-                       if (!options.rect) {\r
-                               options.rect = {\r
-                                       left : 0, top : 0, width : w, height : h\r
-                               };\r
-                       }\r
-                       var validAction = false;\r
-                       if (Pixastic.Actions[actionName] && typeof Pixastic.Actions[actionName].process == "function") {\r
-                               validAction = true;\r
-                       }\r
-                       if (!validAction) {\r
-                               if (Pixastic.debug) writeDebug("Invalid action \"" + actionName + "\". Maybe file not included?");\r
-                               return false;\r
-                       }\r
-                       if (!Pixastic.Actions[actionName].checkSupport()) {\r
-                               if (Pixastic.debug) writeDebug("Action \"" + actionName + "\" not supported by this browser.");\r
-                               return false;\r
-                       }\r
-\r
-                       if (Pixastic.Client.hasCanvas()) {\r
-                               canvas.width = w;\r
-                               canvas.height = h;\r
-                               canvas.style.width = w+"px";\r
-                               canvas.style.height = h+"px";\r
-                               ctx.drawImage(dataImg,0,0,w,h);\r
-\r
-                               if (!img.__pixastic_org_image) {\r
-                                       canvas.__pixastic_org_image = img;\r
-                                       canvas.__pixastic_org_width = w;\r
-                                       canvas.__pixastic_org_height = h;\r
-                               } else {\r
-                                       canvas.__pixastic_org_image = img.__pixastic_org_image;\r
-                                       canvas.__pixastic_org_width = img.__pixastic_org_width;\r
-                                       canvas.__pixastic_org_height = img.__pixastic_org_height;\r
-                               }\r
-\r
-                       } else if (Pixastic.Client.isIE() && typeof img.__pixastic_org_style == "undefined") {\r
-                               img.__pixastic_org_style = img.style.cssText;\r
-                       }\r
-\r
-                       var params = {\r
-                               image : img,\r
-                               canvas : canvas,\r
-                               width : w,\r
-                               height : h,\r
-                               useData : true,\r
-                               options : options\r
-                       }\r
-\r
-                       // Ok, let's do it!\r
-\r
-                       var res = Pixastic.Actions[actionName].process(params);\r
-\r
-                       if (!res) {\r
-                               return false;\r
-                       }\r
-\r
-                       if (Pixastic.Client.hasCanvas()) {\r
-                               if (params.useData) {\r
-                                       if (Pixastic.Client.hasCanvasImageData()) {\r
-                                               canvas.getContext("2d").putImageData(params.canvasData, options.rect.left, options.rect.top);\r
-\r
-                                               // Opera doesn't seem to update the canvas until we draw something on it, lets draw a 0x0 rectangle.\r
-                                               canvas.getContext("2d").fillRect(0,0,0,0);\r
-                                       }\r
-                               }\r
-\r
-                               if (!options.leaveDOM) {\r
-                                       // copy properties and stuff from the source image\r
-                                       canvas.title = img.title;\r
-                                       canvas.imgsrc = img.imgsrc;\r
-                                       if (!imageIsCanvas) canvas.alt  = img.alt;\r
-                                       if (!imageIsCanvas) canvas.imgsrc = img.src;\r
-                                       canvas.className = img.className;\r
-                                       canvas.style.cssText = img.style.cssText;\r
-                                       canvas.name = img.name;\r
-                                       canvas.tabIndex = img.tabIndex;\r
-                                       canvas.id = img.id;\r
-                                       if (img.parentNode && img.parentNode.replaceChild) {\r
-                                               img.parentNode.replaceChild(canvas, img);\r
-                                       }\r
-                               }\r
-\r
-                               options.resultCanvas = canvas;\r
-\r
-                               return canvas;\r
-                       }\r
-\r
-                       return img;\r
-               },\r
-\r
-               prepareData : function(params, getCopy) {\r
-                       var ctx = params.canvas.getContext("2d");\r
-                       var rect = params.options.rect;\r
-                       var dataDesc = ctx.getImageData(rect.left, rect.top, rect.width, rect.height);\r
-                       var data = dataDesc.data;\r
-                       if (!getCopy) params.canvasData = dataDesc;\r
-                       return data;\r
-               },\r
-\r
-               // load the image file\r
-               process : function(img, actionName, options, callback)\r
-               {\r
-                       if (img.tagName.toLowerCase() == "img") {\r
-                               var dataImg = new Image();\r
-                               dataImg.src = img.src;\r
-                               if (dataImg.complete) {\r
-                                       var res = Pixastic.applyAction(img, dataImg, actionName, options);\r
-                                       if (callback) callback(res);\r
-                                       return res;\r
-                               } else {\r
-                                       dataImg.onload = function() {\r
-                                               var res = Pixastic.applyAction(img, dataImg, actionName, options)\r
-                                               if (callback) callback(res);\r
-                                       }\r
-                               }\r
-                       }\r
-                       if (img.tagName.toLowerCase() == "canvas") {\r
-                               var res = Pixastic.applyAction(img, img, actionName, options);\r
-                               if (callback) callback(res);\r
-                               return res;\r
-                       }\r
-               },\r
-\r
-               revert : function(img) {\r
-                       if (Pixastic.Client.hasCanvas()) {\r
-                               if (img.tagName.toLowerCase() == "canvas" && img.__pixastic_org_image) {\r
-                                       img.width = img.__pixastic_org_width;\r
-                                       img.height = img.__pixastic_org_height;\r
-                                       img.getContext("2d").drawImage(img.__pixastic_org_image, 0, 0);\r
-\r
-                                       if (img.parentNode && img.parentNode.replaceChild) {\r
-                                               img.parentNode.replaceChild(img.__pixastic_org_image, img);\r
-                                       }\r
-\r
-                                       return img;\r
-                               }\r
-                       } else if (Pixastic.Client.isIE() && typeof img.__pixastic_org_style != "undefined") {\r
-                               img.style.cssText = img.__pixastic_org_style;\r
-                       }\r
-               },\r
-\r
-               Client : {\r
-                       hasCanvas : (function() {\r
-                               var c = document.createElement("canvas");\r
-                               var val = false;\r
-                               try {\r
-                                       val = !!((typeof c.getContext == "function") && c.getContext("2d"));\r
-                               } catch(e) {}\r
-                               return function() {\r
-                                       return val;\r
-                               }\r
-                       })(),\r
-\r
-                       hasCanvasImageData : (function() {\r
-                               var c = document.createElement("canvas");\r
-                               var val = false;\r
-                               var ctx;\r
-                               try {\r
-                                       if (typeof c.getContext == "function" && (ctx = c.getContext("2d"))) {\r
-                                               val = (typeof ctx.getImageData == "function");\r
-                                       }\r
-                               } catch(e) {}\r
-                               return function() {\r
-                                       return val;\r
-                               }\r
-                       })(),\r
-\r
-                       isIE : function() {\r
-                               return !!document.all && !!window.attachEvent && !window.opera;\r
-                       }\r
-               },\r
-\r
-               Actions : {}\r
-       }\r
-\r
-\r
-})();\r
-/*\r
- * Pixastic Lib - jQuery plugin\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-if (typeof jQuery != "undefined" && jQuery && jQuery.fn) {\r
-       jQuery.fn.pixastic = function(action, options) {\r
-               var newElements = [];\r
-               this.each(\r
-                       function () {\r
-                               if (this.tagName.toLowerCase() == "img" && !this.complete) {\r
-                                       return;\r
-                               }\r
-                               var res = Pixastic.process(this, action, options);\r
-                               if (res) {\r
-                                       newElements.push(res);\r
-                               }\r
-                       }\r
-               );\r
-               if (newElements.length > 0)\r
-                       return jQuery(newElements);\r
-               else\r
-                       return this;\r
-       };\r
-\r
-};\r
-/*\r
- * Pixastic Lib - Blend - v0.1.1\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.blend = {\r
-\r
-       process : function(params) {\r
-               var amount = parseFloat(params.options.amount);\r
-               var mode = (params.options.mode || "normal").toLowerCase();\r
-               var image = params.options.image;\r
-\r
-               amount = Math.max(0,Math.min(1,amount));\r
-\r
-               if (!image) return false;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var rect = params.options.rect;\r
-                       var data = Pixastic.prepareData(params);\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       params.useData = false;\r
-\r
-                       var otherCanvas = document.createElement("canvas");\r
-                       otherCanvas.width = params.canvas.width;\r
-                       otherCanvas.height = params.canvas.height;\r
-                       var otherCtx = otherCanvas.getContext("2d");\r
-                       otherCtx.drawImage(image,0,0);\r
-\r
-                       var params2 = {canvas:otherCanvas,options:params.options};\r
-                       var data2 = Pixastic.prepareData(params2);\r
-                       var dataDesc2 = params2.canvasData;\r
-\r
-                       var p = w*h;\r
-                       var pix = p*4;\r
-                       var pix1, pix2;\r
-                       var r1, g1, b1;\r
-                       var r2, g2, b2;\r
-                       var r3, g3, b3;\r
-                       var r4, g4, b4;\r
-\r
-                       var dataChanged = false;\r
-\r
-                       switch (mode) {\r
-                               case "normal" : \r
-                                       //while (p--) {\r
-                                       //      data2[pix-=4] = data2[pix];\r
-                                       //      data2[pix1=pix+1] = data2[pix1];\r
-                                       //      data2[pix2=pix+2] = data2[pix2];\r
-                                       //}\r
-                                       break;\r
-\r
-                               case "multiply" : \r
-                                       while (p--) {\r
-                                               data2[pix-=4] = data[pix] * data2[pix] / 255;\r
-                                               data2[pix1=pix+1] = data[pix1] * data2[pix1] / 255;\r
-                                               data2[pix2=pix+2] = data[pix2] * data2[pix2] / 255;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "lighten" : \r
-                                       while (p--) {\r
-                                               if ((r1 = data[pix-=4]) > data2[pix])\r
-                                                       data2[pix] = r1;\r
-                                               if ((g1 = data[pix1=pix+1]) > data2[pix1])\r
-                                                       data2[pix1] = g1;\r
-                                               if ((b1 = data[pix2=pix+2]) > data2[pix2])\r
-                                                       data2[pix2] = b1;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "darken" : \r
-                                       while (p--) {\r
-                                               if ((r1 = data[pix-=4]) < data2[pix])\r
-                                                       data2[pix] = r1;\r
-                                               if ((g1 = data[pix1=pix+1]) < data2[pix1])\r
-                                                       data2[pix1] = g1;\r
-                                               if ((b1 = data[pix2=pix+2]) < data2[pix2])\r
-                                                       data2[pix2] = b1;\r
-\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "darkercolor" : \r
-                                       while (p--) {\r
-                                               if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) <= (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {\r
-                                                       data2[pix] = r1;\r
-                                                       data2[pix1] = g1;\r
-                                                       data2[pix2] = b1;\r
-                                               }\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "lightercolor" : \r
-                                       while (p--) {\r
-                                               if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) > (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {\r
-                                                       data2[pix] = r1;\r
-                                                       data2[pix1] = g1;\r
-                                                       data2[pix2] = b1;\r
-                                               }\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "lineardodge" : \r
-                                       otherCtx.globalCompositeOperation = "source-over";\r
-                                       otherCtx.drawImage(params.canvas, 0, 0);\r
-                                       otherCtx.globalCompositeOperation = "lighter";\r
-                                       otherCtx.drawImage(image, 0, 0);\r
-\r
-                                       /*\r
-                                       while (p--) {\r
-                                               if ((r3 = data[pix-=4] + data2[pix]) > 255)\r
-                                                       data2[pix] = 255;\r
-                                               else\r
-                                                       data2[pix] = r3;\r
-                                               if ((g3 = data[pix1=pix+1] + data2[pix1]) > 255)\r
-                                                       data2[pix1] = 255;\r
-                                               else\r
-                                                       data2[pix1] = g3;\r
-                                               if ((b3 = data[pix2=pix+2] + data2[pix2]) > 255)\r
-                                                       data2[pix2] = 255;\r
-                                               else\r
-                                                       data2[pix2] = b3;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       */\r
-\r
-                                       break;\r
-\r
-                               case "linearburn" : \r
-                                       while (p--) {\r
-                                               if ((r3 = data[pix-=4] + data2[pix]) < 255)\r
-                                                       data2[pix] = 0;\r
-                                               else\r
-                                                       data2[pix] = (r3 - 255);\r
-                                               if ((g3 = data[pix1=pix+1] + data2[pix1]) < 255)\r
-                                                       data2[pix1] = 0;\r
-                                               else\r
-                                                       data2[pix1] = (g3 - 255);\r
-                                               if ((b3 = data[pix2=pix+2] + data2[pix2]) < 255)\r
-                                                       data2[pix2] = 0;\r
-                                               else\r
-                                                       data2[pix2] = (b3 - 255);\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "difference" : \r
-                                       while (p--) {\r
-                                               if ((r3 = data[pix-=4] - data2[pix]) < 0)\r
-                                                       data2[pix] = -r3;\r
-                                               else\r
-                                                       data2[pix] = r3;\r
-                                               if ((g3 = data[pix1=pix+1] - data2[pix1]) < 0)\r
-                                                       data2[pix1] = -g3;\r
-                                               else\r
-                                                       data2[pix1] = g3;\r
-                                               if ((b3 = data[pix2=pix+2] - data2[pix2]) < 0)\r
-                                                       data2[pix2] = -b3;\r
-                                               else\r
-                                                       data2[pix2] = b3;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "screen" : \r
-                                       while (p--) {\r
-                                               data2[pix-=4] = (255 - ( ((255-data2[pix])*(255-data[pix])) >> 8));\r
-                                               data2[pix1=pix+1] = (255 - ( ((255-data2[pix1])*(255-data[pix1])) >> 8));\r
-                                               data2[pix2=pix+2] = (255 - ( ((255-data2[pix2])*(255-data[pix2])) >> 8));\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "exclusion" : \r
-                                       var div_2_255 = 2 / 255;\r
-                                       while (p--) {\r
-                                               data2[pix-=4] = (r1 = data[pix]) - (r1 * div_2_255 - 1) * data2[pix];\r
-                                               data2[pix1=pix+1] = (g1 = data[pix1]) - (g1 * div_2_255 - 1) * data2[pix1];\r
-                                               data2[pix2=pix+2] = (b1 = data[pix2]) - (b1 * div_2_255 - 1) * data2[pix2];\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "overlay" : \r
-                                       var div_2_255 = 2 / 255;\r
-                                       while (p--) {\r
-                                               if ((r1 = data[pix-=4]) < 128)\r
-                                                       data2[pix] = data2[pix]*r1*div_2_255;\r
-                                               else\r
-                                                       data2[pix] = 255 - (255-data2[pix])*(255-r1)*div_2_255;\r
-\r
-                                               if ((g1 = data[pix1=pix+1]) < 128)\r
-                                                       data2[pix1] = data2[pix1]*g1*div_2_255;\r
-                                               else\r
-                                                       data2[pix1] = 255 - (255-data2[pix1])*(255-g1)*div_2_255;\r
-\r
-                                               if ((b1 = data[pix2=pix+2]) < 128)\r
-                                                       data2[pix2] = data2[pix2]*b1*div_2_255;\r
-                                               else\r
-                                                       data2[pix2] = 255 - (255-data2[pix2])*(255-b1)*div_2_255;\r
-\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "softlight" : \r
-                                       var div_2_255 = 2 / 255;\r
-                                       while (p--) {\r
-                                               if ((r1 = data[pix-=4]) < 128)\r
-                                                       data2[pix] = ((data2[pix]>>1) + 64) * r1 * div_2_255;\r
-                                               else\r
-                                                       data2[pix] = 255 - (191 - (data2[pix]>>1)) * (255-r1) * div_2_255;\r
-\r
-                                               if ((g1 = data[pix1=pix+1]) < 128)\r
-                                                       data2[pix1] = ((data2[pix1]>>1)+64) * g1 * div_2_255;\r
-                                               else\r
-                                                       data2[pix1] = 255 - (191 - (data2[pix1]>>1)) * (255-g1) * div_2_255;\r
-\r
-                                               if ((b1 = data[pix2=pix+2]) < 128)\r
-                                                       data2[pix2] = ((data2[pix2]>>1)+64) * b1 * div_2_255;\r
-                                               else\r
-                                                       data2[pix2] = 255 - (191 - (data2[pix2]>>1)) * (255-b1) * div_2_255;\r
-\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "hardlight" : \r
-                                       var div_2_255 = 2 / 255;\r
-                                       while (p--) {\r
-                                               if ((r2 = data2[pix-=4]) < 128)\r
-                                                       data2[pix] = data[pix] * r2 * div_2_255;\r
-                                               else\r
-                                                       data2[pix] = 255 - (255-data[pix]) * (255-r2) * div_2_255;\r
-\r
-                                               if ((g2 = data2[pix1=pix+1]) < 128)\r
-                                                       data2[pix1] = data[pix1] * g2 * div_2_255;\r
-                                               else\r
-                                                       data2[pix1] = 255 - (255-data[pix1]) * (255-g2) * div_2_255;\r
-\r
-                                               if ((b2 = data2[pix2=pix+2]) < 128)\r
-                                                       data2[pix2] = data[pix2] * b2 * div_2_255;\r
-                                               else\r
-                                                       data2[pix2] = 255 - (255-data[pix2]) * (255-b2) * div_2_255;\r
-\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "colordodge" : \r
-                                       while (p--) {\r
-                                               if ((r3 = (data[pix-=4]<<8)/(255-(r2 = data2[pix]))) > 255 || r2 == 255)\r
-                                                       data2[pix] = 255;\r
-                                               else\r
-                                                       data2[pix] = r3;\r
-\r
-                                               if ((g3 = (data[pix1=pix+1]<<8)/(255-(g2 = data2[pix1]))) > 255 || g2 == 255)\r
-                                                       data2[pix1] = 255;\r
-                                               else\r
-                                                       data2[pix1] = g3;\r
-\r
-                                               if ((b3 = (data[pix2=pix+2]<<8)/(255-(b2 = data2[pix2]))) > 255 || b2 == 255)\r
-                                                       data2[pix2] = 255;\r
-                                               else\r
-                                                       data2[pix2] = b3;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "colorburn" : \r
-                                       while (p--) {\r
-                                               if ((r3 = 255-((255-data[pix-=4])<<8)/data2[pix]) < 0 || data2[pix] == 0)\r
-                                                       data2[pix] = 0;\r
-                                               else\r
-                                                       data2[pix] = r3;\r
-\r
-                                               if ((g3 = 255-((255-data[pix1=pix+1])<<8)/data2[pix1]) < 0 || data2[pix1] == 0)\r
-                                                       data2[pix1] = 0;\r
-                                               else\r
-                                                       data2[pix1] = g3;\r
-\r
-                                               if ((b3 = 255-((255-data[pix2=pix+2])<<8)/data2[pix2]) < 0 || data2[pix2] == 0)\r
-                                                       data2[pix2] = 0;\r
-                                               else\r
-                                                       data2[pix2] = b3;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "linearlight" : \r
-                                       while (p--) {\r
-                                               if ( ((r3 = 2*(r2=data2[pix-=4])+data[pix]-256) < 0) || (r2 < 128 && r3 < 0)) {\r
-                                                       data2[pix] = 0\r
-                                               } else {\r
-                                                       if (r3 > 255)\r
-                                                               data2[pix] = 255;\r
-                                                       else\r
-                                                               data2[pix] = r3;\r
-                                               }\r
-                                               if ( ((g3 = 2*(g2=data2[pix1=pix+1])+data[pix1]-256) < 0) || (g2 < 128 && g3 < 0)) {\r
-                                                       data2[pix1] = 0\r
-                                               } else {\r
-                                                       if (g3 > 255)\r
-                                                               data2[pix1] = 255;\r
-                                                       else\r
-                                                               data2[pix1] = g3;\r
-                                               }\r
-                                               if ( ((b3 = 2*(b2=data2[pix2=pix+2])+data[pix2]-256) < 0) || (b2 < 128 && b3 < 0)) {\r
-                                                       data2[pix2] = 0\r
-                                               } else {\r
-                                                       if (b3 > 255)\r
-                                                               data2[pix2] = 255;\r
-                                                       else\r
-                                                               data2[pix2] = b3;\r
-                                               }\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "vividlight" : \r
-                                       while (p--) {\r
-                                               if ((r2=data2[pix-=4]) < 128) {\r
-                                                       if (r2) {\r
-                                                               if ((r3 = 255 - ((255-data[pix])<<8) / (2*r2)) < 0) \r
-                                                                       data2[pix] = 0;\r
-                                                               else\r
-                                                                       data2[pix] = r3\r
-                                                       } else {\r
-                                                               data2[pix] = 0;\r
-                                                       }\r
-                                               } else if ((r3 = (r4=2*r2-256)) < 255) {\r
-                                                       if ((r3 = (data[pix]<<8)/(255-r4)) > 255) \r
-                                                               data2[pix] = 255;\r
-                                                       else\r
-                                                               data2[pix] = r3;\r
-                                               } else {\r
-                                                       if (r3 < 0) \r
-                                                               data2[pix] = 0;\r
-                                                       else\r
-                                                               data2[pix] = r3\r
-                                               }\r
-\r
-                                               if ((g2=data2[pix1=pix+1]) < 128) {\r
-                                                       if (g2) {\r
-                                                               if ((g3 = 255 - ((255-data[pix1])<<8) / (2*g2)) < 0) \r
-                                                                       data2[pix1] = 0;\r
-                                                               else\r
-                                                                       data2[pix1] = g3;\r
-                                                       } else {\r
-                                                               data2[pix1] = 0;\r
-                                                       }\r
-                                               } else if ((g3 = (g4=2*g2-256)) < 255) {\r
-                                                       if ((g3 = (data[pix1]<<8)/(255-g4)) > 255)\r
-                                                               data2[pix1] = 255;\r
-                                                       else\r
-                                                               data2[pix1] = g3;\r
-                                               } else {\r
-                                                       if (g3 < 0) \r
-                                                               data2[pix1] = 0;\r
-                                                       else\r
-                                                               data2[pix1] = g3;\r
-                                               }\r
-\r
-                                               if ((b2=data2[pix2=pix+2]) < 128) {\r
-                                                       if (b2) {\r
-                                                               if ((b3 = 255 - ((255-data[pix2])<<8) / (2*b2)) < 0) \r
-                                                                       data2[pix2] = 0;\r
-                                                               else\r
-                                                                       data2[pix2] = b3;\r
-                                                       } else {\r
-                                                               data2[pix2] = 0;\r
-                                                       }\r
-                                               } else if ((b3 = (b4=2*b2-256)) < 255) {\r
-                                                       if ((b3 = (data[pix2]<<8)/(255-b4)) > 255) \r
-                                                               data2[pix2] = 255;\r
-                                                       else\r
-                                                               data2[pix2] = b3;\r
-                                               } else {\r
-                                                       if (b3 < 0) \r
-                                                               data2[pix2] = 0;\r
-                                                       else\r
-                                                               data2[pix2] = b3;\r
-                                               }\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "pinlight" : \r
-                                       while (p--) {\r
-                                               if ((r2=data2[pix-=4]) < 128)\r
-                                                       if ((r1=data[pix]) < (r4=2*r2))\r
-                                                               data2[pix] = r1;\r
-                                                       else\r
-                                                               data2[pix] = r4;\r
-                                               else\r
-                                                       if ((r1=data[pix]) > (r4=2*r2-256))\r
-                                                               data2[pix] = r1;\r
-                                                       else\r
-                                                               data2[pix] = r4;\r
-\r
-                                               if ((g2=data2[pix1=pix+1]) < 128)\r
-                                                       if ((g1=data[pix1]) < (g4=2*g2))\r
-                                                               data2[pix1] = g1;\r
-                                                       else\r
-                                                               data2[pix1] = g4;\r
-                                               else\r
-                                                       if ((g1=data[pix1]) > (g4=2*g2-256))\r
-                                                               data2[pix1] = g1;\r
-                                                       else\r
-                                                               data2[pix1] = g4;\r
-\r
-                                               if ((r2=data2[pix2=pix+2]) < 128)\r
-                                                       if ((r1=data[pix2]) < (r4=2*r2))\r
-                                                               data2[pix2] = r1;\r
-                                                       else\r
-                                                               data2[pix2] = r4;\r
-                                               else\r
-                                                       if ((r1=data[pix2]) > (r4=2*r2-256))\r
-                                                               data2[pix2] = r1;\r
-                                                       else\r
-                                                               data2[pix2] = r4;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "hardmix" : \r
-                                       while (p--) {\r
-                                               if ((r2 = data2[pix-=4]) < 128)\r
-                                                       if (255 - ((255-data[pix])<<8)/(2*r2) < 128 || r2 == 0)\r
-                                                               data2[pix] = 0;\r
-                                                       else\r
-                                                               data2[pix] = 255;\r
-                                               else if ((r4=2*r2-256) < 255 && (data[pix]<<8)/(255-r4) < 128)\r
-                                                       data2[pix] = 0;\r
-                                               else\r
-                                                       data2[pix] = 255;\r
-\r
-                                               if ((g2 = data2[pix1=pix+1]) < 128)\r
-                                                       if (255 - ((255-data[pix1])<<8)/(2*g2) < 128 || g2 == 0)\r
-                                                               data2[pix1] = 0;\r
-                                                       else\r
-                                                               data2[pix1] = 255;\r
-                                               else if ((g4=2*g2-256) < 255 && (data[pix1]<<8)/(255-g4) < 128)\r
-                                                       data2[pix1] = 0;\r
-                                               else\r
-                                                       data2[pix1] = 255;\r
-\r
-                                               if ((b2 = data2[pix2=pix+2]) < 128)\r
-                                                       if (255 - ((255-data[pix2])<<8)/(2*b2) < 128 || b2 == 0)\r
-                                                               data2[pix2] = 0;\r
-                                                       else\r
-                                                               data2[pix2] = 255;\r
-                                               else if ((b4=2*b2-256) < 255 && (data[pix2]<<8)/(255-b4) < 128)\r
-                                                       data2[pix2] = 0;\r
-                                               else\r
-                                                       data2[pix2] = 255;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-                       }\r
-\r
-                       if (dataChanged) \r
-                               otherCtx.putImageData(dataDesc2,0,0);\r
-\r
-                       var ctx = params.canvas.getContext("2d");\r
-                       ctx.save();\r
-                       ctx.globalAlpha = amount;\r
-                       ctx.drawImage(\r
-                               otherCanvas,\r
-                               0,0,rect.width,rect.height,\r
-                               rect.left,rect.top,rect.width,rect.height\r
-                       );\r
-                       ctx.globalAlpha = 1;\r
-                       ctx.restore();\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}/*\r
- * Pixastic Lib - Blur filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.blur = {\r
-       process : function(params) {\r
-\r
-               if (typeof params.options.fixMargin == "undefined")\r
-                       params.options.fixMargin = true;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var dataCopy = Pixastic.prepareData(params, true)\r
-\r
-                       /*\r
-                       var kernel = [\r
-                               [0.5,   1,      0.5],\r
-                               [1,     2,      1],\r
-                               [0.5,   1,      0.5]\r
-                       ];\r
-                       */\r
-\r
-                       var kernel = [\r
-                               [0,     1,      0],\r
-                               [1,     2,      1],\r
-                               [0,     1,      0]\r
-                       ];\r
-\r
-                       var weight = 0;\r
-                       for (var i=0;i<3;i++) {\r
-                               for (var j=0;j<3;j++) {\r
-                                       weight += kernel[i][j];\r
-                               }\r
-                       }\r
-\r
-                       weight = 1 / (weight*2);\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-\r
-                               var prevY = (y == 1) ? 0 : y-2;\r
-                               var nextY = (y == h) ? y - 1 : y;\r
-\r
-                               var offsetYPrev = prevY*w*4;\r
-                               var offsetYNext = nextY*w*4;\r
-\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
-                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
-       \r
-                                       data[offset] = (\r
-                                               /*\r
-                                               dataCopy[offsetPrev - 4]\r
-                                               + dataCopy[offsetPrev+4] \r
-                                               + dataCopy[offsetNext - 4]\r
-                                               + dataCopy[offsetNext+4]\r
-                                               + \r
-                                               */\r
-                                               (dataCopy[offsetPrev]\r
-                                               + dataCopy[offset-4]\r
-                                               + dataCopy[offset+4]\r
-                                               + dataCopy[offsetNext])         * 2\r
-                                               + dataCopy[offset]              * 4\r
-                                               ) * weight;\r
-\r
-                                       data[offset+1] = (\r
-                                               /*\r
-                                               dataCopy[offsetPrev - 3]\r
-                                               + dataCopy[offsetPrev+5] \r
-                                               + dataCopy[offsetNext - 3] \r
-                                               + dataCopy[offsetNext+5]\r
-                                               + \r
-                                               */\r
-                                               (dataCopy[offsetPrev+1]\r
-                                               + dataCopy[offset-3]\r
-                                               + dataCopy[offset+5]\r
-                                               + dataCopy[offsetNext+1])       * 2\r
-                                               + dataCopy[offset+1]            * 4\r
-                                               ) * weight;\r
-\r
-                                       data[offset+2] = (\r
-                                               /*\r
-                                               dataCopy[offsetPrev - 2] \r
-                                               + dataCopy[offsetPrev+6] \r
-                                               + dataCopy[offsetNext - 2] \r
-                                               + dataCopy[offsetNext+6]\r
-                                               + \r
-                                               */\r
-                                               (dataCopy[offsetPrev+2]\r
-                                               + dataCopy[offset-2]\r
-                                               + dataCopy[offset+6]\r
-                                               + dataCopy[offsetNext+2])       * 2\r
-                                               + dataCopy[offset+2]            * 4\r
-                                               ) * weight;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=1.5)";\r
-\r
-                       if (params.options.fixMargin) {\r
-                               params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - 2 + "px";\r
-                               params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - 2 + "px";\r
-                       }\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
-       }\r
-}/*\r
- * Pixastic Lib - Blur Fast - v0.1.1\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.blurfast = {\r
-       process : function(params) {\r
-\r
-               var amount = parseFloat(params.options.amount)||0;\r
-               var clear = !!(params.options.clear && params.options.clear != "false");\r
-\r
-               amount = Math.max(0,Math.min(5,amount));\r
-\r
-               if (Pixastic.Client.hasCanvas()) {\r
-                       var rect = params.options.rect;\r
-\r
-                       var ctx = params.canvas.getContext("2d");\r
-                       ctx.save();\r
-                       ctx.beginPath();\r
-                       ctx.rect(rect.left, rect.top, rect.width, rect.height);\r
-                       ctx.clip();\r
-\r
-                       var scale = 2;\r
-                       var smallWidth = Math.round(params.width / scale);\r
-                       var smallHeight = Math.round(params.height / scale);\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = smallWidth;\r
-                       copy.height = smallHeight;\r
-\r
-                       var clear = false;\r
-                       var steps = Math.round(amount * 20);\r
-\r
-                       var copyCtx = copy.getContext("2d");\r
-                       for (var i=0;i<steps;i++) {\r
-                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));\r
-                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));\r
-       \r
-                               copyCtx.clearRect(0,0,smallWidth,smallHeight);\r
-       \r
-                               copyCtx.drawImage(\r
-                                       params.canvas,\r
-                                       0,0,params.width,params.height,\r
-                                       0,0,scaledWidth,scaledHeight\r
-                               );\r
-       \r
-                               if (clear)\r
-                                       ctx.clearRect(rect.left,rect.top,rect.width,rect.height);\r
-       \r
-                               ctx.drawImage(\r
-                                       copy,\r
-                                       0,0,scaledWidth,scaledHeight,\r
-                                       0,0,params.width,params.height\r
-                               );\r
-                       }\r
-\r
-                       ctx.restore();\r
-\r
-                       params.useData = false;\r
-                       return true;\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       var radius = 10 * amount;\r
-                       params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=" + radius + ")";\r
-\r
-                       if (params.options.fixMargin || 1) {\r
-                               params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - Math.round(radius) + "px";\r
-                               params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - Math.round(radius) + "px";\r
-                       }\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());\r
-       }\r
-}\r
-/*\r
- * Pixastic Lib - Brightness/Contrast filter - v0.1.1\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.brightness = {\r
-\r
-       process : function(params) {\r
-\r
-               var brightness = parseInt(params.options.brightness,10) || 0;\r
-               var contrast = parseFloat(params.options.contrast)||0;\r
-               var legacy = !!(params.options.legacy && params.options.legacy != "false");\r
-\r
-               if (legacy) {\r
-                       brightness = Math.min(150,Math.max(-150,brightness));\r
-               } else {\r
-                       var brightMul = 1 + Math.min(150,Math.max(-150,brightness)) / 150;\r
-               }\r
-               contrast = Math.max(0,contrast+1);\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var p = w*h;\r
-                       var pix = p*4, pix1, pix2;\r
-\r
-                       var mul, add;\r
-                       if (contrast != 1) {\r
-                               if (legacy) {\r
-                                       mul = contrast;\r
-                                       add = (brightness - 128) * contrast + 128;\r
-                               } else {\r
-                                       mul = brightMul * contrast;\r
-                                       add = - contrast * 128 + 128;\r
-                               }\r
-                       } else {  // this if-then is not necessary anymore, is it?\r
-                               if (legacy) {\r
-                                       mul = 1;\r
-                                       add = brightness;\r
-                               } else {\r
-                                       mul = brightMul;\r
-                                       add = 0;\r
-                               }\r
-                       }\r
-                       var r, g, b;\r
-                       while (p--) {\r
-                               if ((r = data[pix-=4] * mul + add) > 255 )\r
-                                       data[pix] = 255;\r
-                               else if (r < 0)\r
-                                       data[pix] = 0;\r
-                               else\r
-                                       data[pix] = r;\r
-\r
-                               if ((g = data[pix1=pix+1] * mul + add) > 255 ) \r
-                                       data[pix1] = 255;\r
-                               else if (g < 0)\r
-                                       data[pix1] = 0;\r
-                               else\r
-                                       data[pix1] = g;\r
-\r
-                               if ((b = data[pix2=pix+2] * mul + add) > 255 ) \r
-                                       data[pix2] = 255;\r
-                               else if (b < 0)\r
-                                       data[pix2] = 0;\r
-                               else\r
-                                       data[pix2] = b;\r
-                       }\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-\r
-/*\r
- * Pixastic Lib - Color adjust filter - v0.1.1\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.coloradjust = {\r
-\r
-       process : function(params) {\r
-               var red = parseFloat(params.options.red) || 0;\r
-               var green = parseFloat(params.options.green) || 0;\r
-               var blue = parseFloat(params.options.blue) || 0;\r
-\r
-               red = Math.round(red*255);\r
-               green = Math.round(green*255);\r
-               blue = Math.round(blue*255);\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var rect = params.options.rect;\r
-\r
-                       var p = rect.width*rect.height;\r
-                       var pix = p*4, pix1, pix2;\r
-\r
-                       var r, g, b;\r
-                       while (p--) {\r
-                               pix -= 4;\r
-\r
-                               if (red) {\r
-                                       if ((r = data[pix] + red) < 0 ) \r
-                                               data[pix] = 0;\r
-                                       else if (r > 255 ) \r
-                                               data[pix] = 255;\r
-                                       else\r
-                                               data[pix] = r;\r
-                               }\r
-\r
-                               if (green) {\r
-                                       if ((g = data[pix1=pix+1] + green) < 0 ) \r
-                                               data[pix1] = 0;\r
-                                       else if (g > 255 ) \r
-                                               data[pix1] = 255;\r
-                                       else\r
-                                               data[pix1] = g;\r
-                               }\r
-\r
-                               if (blue) {\r
-                                       if ((b = data[pix2=pix+2] + blue) < 0 ) \r
-                                               data[pix2] = 0;\r
-                                       else if (b > 255 ) \r
-                                               data[pix2] = 255;\r
-                                       else\r
-                                               data[pix2] = b;\r
-                               }\r
-                       }\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData());\r
-       }\r
-}\r
-/*\r
- * Pixastic Lib - Histogram - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-\r
-Pixastic.Actions.colorhistogram = {\r
-\r
-       array256 : function(default_value) {\r
-               arr = [];\r
-               for (var i=0; i<256; i++) { arr[i] = default_value; }\r
-               return arr\r
-       },\r
\r
-       process : function(params) {\r
-               var values = [];\r
-               if (typeof params.options.returnValue != "object") {\r
-                       params.options.returnValue = {rvals:[], gvals:[], bvals:[]};\r
-               }\r
-               var paint = !!(params.options.paint);\r
-\r
-               var returnValue = params.options.returnValue;\r
-               if (typeof returnValue.values != "array") {\r
-                       returnValue.rvals = [];\r
-                       returnValue.gvals = [];\r
-                       returnValue.bvals = [];\r
-               }\r
\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       params.useData = false;\r
\r
-                       var rvals = this.array256(0);\r
-                       var gvals = this.array256(0);\r
-                       var bvals = this.array256(0);\r
\r
-                       var rect = params.options.rect;\r
-\r
-                       var p = rect.width*rect.height;\r
-                       var pix = p*4;\r
-                       while (p--) {\r
-                               rvals[data[pix-=4]]++;\r
-                               gvals[data[pix+1]]++;\r
-                               bvals[data[pix+2]]++;\r
-                       }\r
\r
-                       returnValue.rvals = rvals;\r
-                       returnValue.gvals = gvals;\r
-                       returnValue.bvals = bvals;\r
-\r
-                       if (paint) {\r
-                               var ctx = params.canvas.getContext("2d");\r
-                               var vals = [rvals, gvals, bvals];\r
-                               for (var v=0;v<3;v++) {\r
-                                       var yoff = (v+1) * params.height / 3;\r
-                                       var maxValue = 0;\r
-                                       for (var i=0;i<256;i++) {\r
-                                               if (vals[v][i] > maxValue)\r
-                                                       maxValue = vals[v][i];\r
-                                       }\r
-                                       var heightScale = params.height / 3 / maxValue;\r
-                                       var widthScale = params.width / 256;\r
-                                       if (v==0) ctx.fillStyle = "rgba(255,0,0,0.5)";\r
-                                       else if (v==1) ctx.fillStyle = "rgba(0,255,0,0.5)";\r
-                                       else if (v==2) ctx.fillStyle = "rgba(0,0,255,0.5)";\r
-                                       for (var i=0;i<256;i++) {\r
-                                               ctx.fillRect(\r
-                                                       i * widthScale, params.height - heightScale * vals[v][i] - params.height + yoff,\r
-                                                       widthScale, vals[v][i] * heightScale\r
-                                               );\r
-                                       }\r
-                               }\r
-                       }\r
-                       return true;\r
-               }\r
-       },\r
-\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}/*\r
- * Pixastic Lib - Crop - v0.1.1\r
- * Copyright (c) 2008-2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.crop = {\r
-       process : function(params) {\r
-               if (Pixastic.Client.hasCanvas()) {\r
-                       var rect = params.options.rect;\r
-\r
-                       var width = rect.width;\r
-                       var height = rect.height;\r
-                       var top = rect.top;\r
-                       var left = rect.left;\r
-\r
-                       if (typeof params.options.left != "undefined")\r
-                               left = parseInt(params.options.left,10);\r
-                       if (typeof params.options.top != "undefined")\r
-                               top = parseInt(params.options.top,10);\r
-                       if (typeof params.options.height != "undefined")\r
-                               width = parseInt(params.options.width,10);\r
-                       if (typeof params.options.height != "undefined")\r
-                               height = parseInt(params.options.height,10);\r
-\r
-                       if (left < 0) left = 0;\r
-                       if (left > params.width-1) left = params.width-1;\r
-\r
-                       if (top < 0) top = 0;\r
-                       if (top > params.height-1) top = params.height-1;\r
-\r
-                       if (width < 1) width = 1;\r
-                       if (left + width > params.width)\r
-                               width = params.width - left;\r
-\r
-                       if (height < 1) height = 1;\r
-                       if (top + height > params.height)\r
-                               height = params.height - top;\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = params.width;\r
-                       copy.height = params.height;\r
-                       copy.getContext("2d").drawImage(params.canvas,0,0);\r
-\r
-                       params.canvas.width = width;\r
-                       params.canvas.height = height;\r
-                       params.canvas.getContext("2d").clearRect(0,0,width,height);\r
-\r
-                       params.canvas.getContext("2d").drawImage(copy,\r
-                               left,top,width,height,\r
-                               0,0,width,height\r
-                       );\r
-\r
-                       params.useData = false;\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvas();\r
-       }\r
-}\r
-\r
-\r
-/*\r
- * Pixastic Lib - Desaturation filter - v0.1.1\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.desaturate = {\r
-\r
-       process : function(params) {\r
-               var useAverage = !!(params.options.average && params.options.average != "false");\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var p = w*h;\r
-                       var pix = p*4, pix1, pix2;\r
-\r
-                       if (useAverage) {\r
-                               while (p--) \r
-                                       data[pix-=4] = data[pix1=pix+1] = data[pix2=pix+2] = (data[pix]+data[pix1]+data[pix2])/3\r
-                       } else {\r
-                               while (p--)\r
-                                       data[pix-=4] = data[pix1=pix+1] = data[pix2=pix+2] = (data[pix]*0.3 + data[pix1]*0.59 + data[pix2]*0.11);\r
-                       }\r
-                       return true;\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       params.image.style.filter += " gray";\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
-       }\r
-}/*\r
- * Pixastic Lib - Edge detection filter - v0.1.1\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.edges = {\r
-       process : function(params) {\r
-\r
-               var mono = !!(params.options.mono && params.options.mono != "false");\r
-               var invert = !!(params.options.invert && params.options.invert != "false");\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var dataCopy = Pixastic.prepareData(params, true)\r
-\r
-                       var c = -1/8;\r
-                       var kernel = [\r
-                               [c,     c,      c],\r
-                               [c,     1,      c],\r
-                               [c,     c,      c]\r
-                       ];\r
-\r
-                       weight = 1/c;\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-\r
-                               var nextY = (y == h) ? y - 1 : y;\r
-                               var prevY = (y == 1) ? 0 : y-2;\r
-\r
-                               var offsetYPrev = prevY*w*4;\r
-                               var offsetYNext = nextY*w*4;\r
-\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
-                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
-       \r
-                                       var r = ((dataCopy[offsetPrev-4]\r
-                                               + dataCopy[offsetPrev]\r
-                                               + dataCopy[offsetPrev+4]\r
-                                               + dataCopy[offset-4]\r
-                                               + dataCopy[offset+4]\r
-                                               + dataCopy[offsetNext-4]\r
-                                               + dataCopy[offsetNext]\r
-                                               + dataCopy[offsetNext+4]) * c\r
-                                               + dataCopy[offset]\r
-                                               ) \r
-                                               * weight;\r
-       \r
-                                       var g = ((dataCopy[offsetPrev-3]\r
-                                               + dataCopy[offsetPrev+1]\r
-                                               + dataCopy[offsetPrev+5]\r
-                                               + dataCopy[offset-3]\r
-                                               + dataCopy[offset+5]\r
-                                               + dataCopy[offsetNext-3]\r
-                                               + dataCopy[offsetNext+1]\r
-                                               + dataCopy[offsetNext+5]) * c\r
-                                               + dataCopy[offset+1])\r
-                                               * weight;\r
-       \r
-                                       var b = ((dataCopy[offsetPrev-2]\r
-                                               + dataCopy[offsetPrev+2]\r
-                                               + dataCopy[offsetPrev+6]\r
-                                               + dataCopy[offset-2]\r
-                                               + dataCopy[offset+6]\r
-                                               + dataCopy[offsetNext-2]\r
-                                               + dataCopy[offsetNext+2]\r
-                                               + dataCopy[offsetNext+6]) * c\r
-                                               + dataCopy[offset+2])\r
-                                               * weight;\r
-\r
-                                       if (mono) {\r
-                                               var brightness = (r*0.3 + g*0.59 + b*0.11)||0;\r
-                                               if (invert) brightness = 255 - brightness;\r
-                                               if (brightness < 0 ) brightness = 0;\r
-                                               if (brightness > 255 ) brightness = 255;\r
-                                               r = g = b = brightness;\r
-                                       } else {\r
-                                               if (invert) {\r
-                                                       r = 255 - r;\r
-                                                       g = 255 - g;\r
-                                                       b = 255 - b;\r
-                                               }\r
-                                               if (r < 0 ) r = 0;\r
-                                               if (g < 0 ) g = 0;\r
-                                               if (b < 0 ) b = 0;\r
-                                               if (r > 255 ) r = 255;\r
-                                               if (g > 255 ) g = 255;\r
-                                               if (b > 255 ) b = 255;\r
-                                       }\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}/*\r
- * Pixastic Lib - Edge detection 2 - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- * \r
- * Contribution by Oliver Hunt (http://nerget.com/, http://nerget.com/canvas/edgeDetection.js). Thanks Oliver!\r
- *\r
- */\r
-\r
-Pixastic.Actions.edges2 = {\r
-       process : function(params) {\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var dataCopy = Pixastic.prepareData(params, true)\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w * 4;\r
-                       var pixel = w4 + 4; // Start at (1,1)\r
-                       var hm1 = h - 1;\r
-                       var wm1 = w - 1;\r
-                       for (var y = 1; y < hm1; ++y) {\r
-                               // Prepare initial cached values for current row\r
-                               var centerRow = pixel - 4;\r
-                               var priorRow = centerRow - w4;\r
-                               var nextRow = centerRow + w4;\r
-                               \r
-                               var r1 = - dataCopy[priorRow]   - dataCopy[centerRow]   - dataCopy[nextRow];\r
-                               var g1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];\r
-                               var b1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];\r
-                               \r
-                               var rp = dataCopy[priorRow += 2];\r
-                               var gp = dataCopy[++priorRow];\r
-                               var bp = dataCopy[++priorRow];\r
-                               \r
-                               var rc = dataCopy[centerRow += 2];\r
-                               var gc = dataCopy[++centerRow];\r
-                               var bc = dataCopy[++centerRow];\r
-                               \r
-                               var rn = dataCopy[nextRow += 2];\r
-                               var gn = dataCopy[++nextRow];\r
-                               var bn = dataCopy[++nextRow];\r
-                               \r
-                               var r2 = - rp - rc - rn;\r
-                               var g2 = - gp - gc - gn;\r
-                               var b2 = - bp - bc - bn;\r
-                               \r
-                               // Main convolution loop\r
-                               for (var x = 1; x < wm1; ++x) {\r
-                                       centerRow = pixel + 4;\r
-                                       priorRow = centerRow - w4;\r
-                                       nextRow = centerRow + w4;\r
-                                       \r
-                                       var r = 127 + r1 - rp - (rc * -8) - rn;\r
-                                       var g = 127 + g1 - gp - (gc * -8) - gn;\r
-                                       var b = 127 + b1 - bp - (bc * -8) - bn;\r
-                                       \r
-                                       r1 = r2;\r
-                                       g1 = g2;\r
-                                       b1 = b2;\r
-                                       \r
-                                       rp = dataCopy[  priorRow];\r
-                                       gp = dataCopy[++priorRow];\r
-                                       bp = dataCopy[++priorRow];\r
-                                       \r
-                                       rc = dataCopy[  centerRow];\r
-                                       gc = dataCopy[++centerRow];\r
-                                       bc = dataCopy[++centerRow];\r
-                                       \r
-                                       rn = dataCopy[  nextRow];\r
-                                       gn = dataCopy[++nextRow];\r
-                                       bn = dataCopy[++nextRow];\r
-                                       \r
-                                       r += (r2 = - rp - rc - rn);\r
-                                       g += (g2 = - gp - gc - gn);\r
-                                       b += (b2 = - bp - bc - bn);\r
-\r
-                                       if (r > 255) r = 255;\r
-                                       if (g > 255) g = 255;\r
-                                       if (b > 255) b = 255;\r
-                                       if (r < 0) r = 0;\r
-                                       if (g < 0) g = 0;\r
-                                       if (b < 0) b = 0;\r
-\r
-                                       data[pixel] = r;\r
-                                       data[++pixel] = g;\r
-                                       data[++pixel] = b;\r
-                                       //data[++pixel] = 255; // alpha\r
-\r
-                                       pixel+=2;\r
-                               }\r
-                               pixel += 8;\r
-                       }\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}/*\r
- * Pixastic Lib - Emboss filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.emboss = {\r
-       process : function(params) {\r
-\r
-               var strength = parseFloat(params.options.strength)||1;\r
-               var greyLevel = typeof params.options.greyLevel != "undefined" ? parseInt(params.options.greyLevel) : 180;\r
-               var direction = params.options.direction||"topleft";\r
-               var blend = !!(params.options.blend && params.options.blend != "false");\r
-\r
-               var dirY = 0;\r
-               var dirX = 0;\r
-\r
-               switch (direction) {\r
-                       case "topleft":                 // top left\r
-                               dirY = -1;\r
-                               dirX = -1;\r
-                               break;\r
-                       case "top":                     // top\r
-                               dirY = -1;\r
-                               dirX = 0;\r
-                               break;\r
-                       case "topright":                        // top right\r
-                               dirY = -1;\r
-                               dirX = 1;\r
-                               break;\r
-                       case "right":                   // right\r
-                               dirY = 0;\r
-                               dirX = 1;\r
-                               break;\r
-                       case "bottomright":                     // bottom right\r
-                               dirY = 1;\r
-                               dirX = 1;\r
-                               break;\r
-                       case "bottom":                  // bottom\r
-                               dirY = 1;\r
-                               dirX = 0;\r
-                               break;\r
-                       case "bottomleft":                      // bottom left\r
-                               dirY = 1;\r
-                               dirX = -1;\r
-                               break;\r
-                       case "left":                    // left\r
-                               dirY = 0;\r
-                               dirX = -1;\r
-                               break;\r
-               }\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var dataCopy = Pixastic.prepareData(params, true)\r
-\r
-                       var invertAlpha = !!params.options.invertAlpha;\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-\r
-                               var otherY = dirY;\r
-                               if (y + otherY < 1) otherY = 0;\r
-                               if (y + otherY > h) otherY = 0;\r
-\r
-                               var offsetYOther = (y-1+otherY)*w*4;\r
-\r
-                               var x = w;\r
-                               do {\r
-                                               var offset = offsetY + (x-1)*4;\r
-\r
-                                               var otherX = dirX;\r
-                                               if (x + otherX < 1) otherX = 0;\r
-                                               if (x + otherX > w) otherX = 0;\r
-\r
-                                               var offsetOther = offsetYOther + (x-1+otherX)*4;\r
-\r
-                                               var dR = dataCopy[offset] - dataCopy[offsetOther];\r
-                                               var dG = dataCopy[offset+1] - dataCopy[offsetOther+1];\r
-                                               var dB = dataCopy[offset+2] - dataCopy[offsetOther+2];\r
-\r
-                                               var dif = dR;\r
-                                               var absDif = dif > 0 ? dif : -dif;\r
-\r
-                                               var absG = dG > 0 ? dG : -dG;\r
-                                               var absB = dB > 0 ? dB : -dB;\r
-\r
-                                               if (absG > absDif) {\r
-                                                       dif = dG;\r
-                                               }\r
-                                               if (absB > absDif) {\r
-                                                       dif = dB;\r
-                                               }\r
-\r
-                                               dif *= strength;\r
-\r
-                                               if (blend) {\r
-                                                       var r = data[offset] + dif;\r
-                                                       var g = data[offset+1] + dif;\r
-                                                       var b = data[offset+2] + dif;\r
-\r
-                                                       data[offset] = (r > 255) ? 255 : (r < 0 ? 0 : r);\r
-                                                       data[offset+1] = (g > 255) ? 255 : (g < 0 ? 0 : g);\r
-                                                       data[offset+2] = (b > 255) ? 255 : (b < 0 ? 0 : b);\r
-                                               } else {\r
-                                                       var grey = greyLevel - dif;\r
-                                                       if (grey < 0) {\r
-                                                               grey = 0;\r
-                                                       } else if (grey > 255) {\r
-                                                               grey = 255;\r
-                                                       }\r
-\r
-                                                       data[offset] = data[offset+1] = data[offset+2] = grey;\r
-                                               }\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-                       return true;\r
-\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       params.image.style.filter += " progid:DXImageTransform.Microsoft.emboss()";\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
-       }\r
-\r
-}\r
-/*\r
- * Pixastic Lib - Flip - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.flip = {\r
-       process : function(params) {\r
-               var rect = params.options.rect;\r
-               var copyCanvas = document.createElement("canvas");\r
-               copyCanvas.width = rect.width;\r
-               copyCanvas.height = rect.height;\r
-               copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);\r
-\r
-               var ctx = params.canvas.getContext("2d");\r
-               ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
-\r
-               if (params.options.axis == "horizontal") {\r
-                       ctx.scale(-1,1);\r
-                       ctx.drawImage(copyCanvas, -rect.left-rect.width, rect.top, rect.width, rect.height)\r
-               } else {\r
-                       ctx.scale(1,-1);\r
-                       ctx.drawImage(copyCanvas, rect.left, -rect.top-rect.height, rect.width, rect.height)\r
-               }\r
-\r
-               params.useData = false;\r
-\r
-               return true;            \r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvas();\r
-       }\r
-}\r
-\r
-/*\r
- * Pixastic Lib - Horizontal flip - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.fliph = {\r
-       process : function(params) {\r
-               if (Pixastic.Client.hasCanvas()) {\r
-                       var rect = params.options.rect;\r
-                       var copyCanvas = document.createElement("canvas");\r
-                       copyCanvas.width = rect.width;\r
-                       copyCanvas.height = rect.height;\r
-                       copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);\r
-\r
-                       var ctx = params.canvas.getContext("2d");\r
-                       ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
-                       ctx.scale(-1,1);\r
-                       ctx.drawImage(copyCanvas, -rect.left-rect.width, rect.top, rect.width, rect.height)\r
-                       params.useData = false;\r
-\r
-                       return true;            \r
-\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       params.image.style.filter += " fliph";\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());\r
-       }\r
-}\r
-\r
-/*\r
- * Pixastic Lib - Vertical flip - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.flipv = {\r
-       process : function(params) {\r
-               if (Pixastic.Client.hasCanvas()) {\r
-                       var rect = params.options.rect;\r
-                       var copyCanvas = document.createElement("canvas");\r
-                       copyCanvas.width = rect.width;\r
-                       copyCanvas.height = rect.height;\r
-                       copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);\r
-\r
-                       var ctx = params.canvas.getContext("2d");\r
-                       ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
-                       ctx.scale(1,-1);\r
-                       ctx.drawImage(copyCanvas, rect.left, -rect.top-rect.height, rect.width, rect.height)\r
-                       params.useData = false;\r
-\r
-                       return true;            \r
-\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       params.image.style.filter += " flipv";\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());\r
-       }\r
-}\r
-\r
-/*\r
- * Pixastic Lib - Glow - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-\r
-Pixastic.Actions.glow = {\r
-       process : function(params) {\r
-\r
-               var amount = (parseFloat(params.options.amount)||0);\r
-               var blurAmount = parseFloat(params.options.radius)||0;\r
-\r
-               amount = Math.min(1,Math.max(0,amount));\r
-               blurAmount = Math.min(5,Math.max(0,blurAmount));\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var rect = params.options.rect;\r
-\r
-                       var blurCanvas = document.createElement("canvas");\r
-                       blurCanvas.width = params.width;\r
-                       blurCanvas.height = params.height;\r
-                       var blurCtx = blurCanvas.getContext("2d");\r
-                       blurCtx.drawImage(params.canvas,0,0);\r
-\r
-                       var scale = 2;\r
-                       var smallWidth = Math.round(params.width / scale);\r
-                       var smallHeight = Math.round(params.height / scale);\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = smallWidth;\r
-                       copy.height = smallHeight;\r
-\r
-                       var clear = true;\r
-                       var steps = Math.round(blurAmount * 20);\r
-\r
-                       var copyCtx = copy.getContext("2d");\r
-                       for (var i=0;i<steps;i++) {\r
-                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));\r
-                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));\r
-       \r
-                               copyCtx.clearRect(0,0,smallWidth,smallHeight);\r
-       \r
-                               copyCtx.drawImage(\r
-                                       blurCanvas,\r
-                                       0,0,params.width,params.height,\r
-                                       0,0,scaledWidth,scaledHeight\r
-                               );\r
-       \r
-                               blurCtx.clearRect(0,0,params.width,params.height);\r
-       \r
-                               blurCtx.drawImage(\r
-                                       copy,\r
-                                       0,0,scaledWidth,scaledHeight,\r
-                                       0,0,params.width,params.height\r
-                               );\r
-                       }\r
-\r
-                       var data = Pixastic.prepareData(params);\r
-                       var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var r = data[offset] + amount * blurData[offset];\r
-                                       var g = data[offset+1] + amount * blurData[offset+1];\r
-                                       var b = data[offset+2] + amount * blurData[offset+2];\r
-       \r
-                                       if (r > 255) r = 255;\r
-                                       if (g > 255) g = 255;\r
-                                       if (b > 255) b = 255;\r
-                                       if (r < 0) r = 0;\r
-                                       if (g < 0) g = 0;\r
-                                       if (b < 0) b = 0;\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
- * Pixastic Lib - Histogram - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.histogram = {\r
-       process : function(params) {\r
-\r
-               var average = !!(params.options.average && params.options.average != "false");\r
-               var paint = !!(params.options.paint && params.options.paint != "false");\r
-               var color = params.options.color || "rgba(255,255,255,0.5)";\r
-               var values = [];\r
-               if (typeof params.options.returnValue != "object") {\r
-                       params.options.returnValue = {values:[]};\r
-               }\r
-               var returnValue = params.options.returnValue;\r
-               if (typeof returnValue.values != "array") {\r
-                       returnValue.values = [];\r
-               }\r
-               values = returnValue.values;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       params.useData = false;\r
-\r
-                       for (var i=0;i<256;i++) {\r
-                               values[i] = 0;\r
-                       }\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-                                       var brightness = average ? \r
-                                               Math.round((data[offset]+data[offset+1]+data[offset+2])/3)\r
-                                               : Math.round(data[offset]*0.3 + data[offset+1]*0.59 + data[offset+2]*0.11);\r
-                                       values[brightness]++;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       if (paint) {\r
-                               var maxValue = 0;\r
-                               for (var i=0;i<256;i++) {\r
-                                       if (values[i] > maxValue) {\r
-                                               maxValue = values[i];\r
-                                       }\r
-                               }\r
-                               var heightScale = params.height / maxValue;\r
-                               var widthScale = params.width / 256;\r
-                               var ctx = params.canvas.getContext("2d");\r
-                               ctx.fillStyle = color;\r
-                               for (var i=0;i<256;i++) {\r
-                                       ctx.fillRect(\r
-                                               i * widthScale, params.height - heightScale * values[i],\r
-                                               widthScale, values[i] * heightScale\r
-                                       );\r
-                               }\r
-                       }\r
-\r
-                       returnValue.values = values;\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-/*\r
- * Pixastic Lib - HSL Adjust  - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.hsl = {\r
-       process : function(params) {\r
-\r
-               var hue = parseInt(params.options.hue,10)||0;\r
-               var saturation = (parseInt(params.options.saturation,10)||0) / 100;\r
-               var lightness = (parseInt(params.options.lightness,10)||0) / 100;\r
-\r
-\r
-               // this seems to give the same result as Photoshop\r
-               if (saturation < 0) {\r
-                       var satMul = 1+saturation;\r
-               } else {\r
-                       var satMul = 1+saturation*2;\r
-               }\r
-\r
-               hue = (hue%360) / 360;\r
-               var hue6 = hue * 6;\r
-\r
-               var rgbDiv = 1 / 255;\r
-\r
-               var light255 = lightness * 255;\r
-               var lightp1 = 1 + lightness;\r
-               var lightm1 = 1 - lightness;\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var r = data[offset];\r
-                                       var g = data[offset+1];\r
-                                       var b = data[offset+2];\r
-\r
-                                       if (hue != 0 || saturation != 0) {\r
-                                               // ok, here comes rgb to hsl + adjust + hsl to rgb, all in one jumbled mess. \r
-                                               // It's not so pretty, but it's been optimized to get somewhat decent performance.\r
-                                               // The transforms were originally adapted from the ones found in Graphics Gems, but have been heavily modified.\r
-                                               var vs = r;\r
-                                               if (g > vs) vs = g;\r
-                                               if (b > vs) vs = b;\r
-                                               var ms = r;\r
-                                               if (g < ms) ms = g;\r
-                                               if (b < ms) ms = b;\r
-                                               var vm = (vs-ms);\r
-                                               var l = (ms+vs)/255 * 0.5;\r
-                                               if (l > 0) {\r
-                                                       if (vm > 0) {\r
-                                                               if (l <= 0.5) {\r
-                                                                       var s = vm / (vs+ms) * satMul;\r
-                                                                       if (s > 1) s = 1;\r
-                                                                       var v = (l * (1+s));\r
-                                                               } else {\r
-                                                                       var s = vm / (510-vs-ms) * satMul;\r
-                                                                       if (s > 1) s = 1;\r
-                                                                       var v = (l+s - l*s);\r
-                                                               }\r
-                                                               if (r == vs) {\r
-                                                                       if (g == ms)\r
-                                                                               var h = 5 + ((vs-b)/vm) + hue6;\r
-                                                                       else\r
-                                                                               var h = 1 - ((vs-g)/vm) + hue6;\r
-                                                               } else if (g == vs) {\r
-                                                                       if (b == ms)\r
-                                                                               var h = 1 + ((vs-r)/vm) + hue6;\r
-                                                                       else\r
-                                                                               var h = 3 - ((vs-b)/vm) + hue6;\r
-                                                               } else {\r
-                                                                       if (r == ms)\r
-                                                                               var h = 3 + ((vs-g)/vm) + hue6;\r
-                                                                       else\r
-                                                                               var h = 5 - ((vs-r)/vm) + hue6;\r
-                                                               }\r
-                                                               if (h < 0) h+=6;\r
-                                                               if (h >= 6) h-=6;\r
-                                                               var m = (l+l-v);\r
-                                                               var sextant = h>>0;\r
-                                                               switch (sextant) {\r
-                                                                       case 0: r = v*255; g = (m+((v-m)*(h-sextant)))*255; b = m*255; break;\r
-                                                                       case 1: r = (v-((v-m)*(h-sextant)))*255; g = v*255; b = m*255; break;\r
-                                                                       case 2: r = m*255; g = v*255; b = (m+((v-m)*(h-sextant)))*255; break;\r
-                                                                       case 3: r = m*255; g = (v-((v-m)*(h-sextant)))*255; b = v*255; break;\r
-                                                                       case 4: r = (m+((v-m)*(h-sextant)))*255; g = m*255; b = v*255; break;\r
-                                                                       case 5: r = v*255; g = m*255; b = (v-((v-m)*(h-sextant)))*255; break;\r
-                                                               }\r
-                                                       }\r
-                                               }\r
-                                       }\r
-\r
-                                       if (lightness < 0) {\r
-                                               r *= lightp1;\r
-                                               g *= lightp1;\r
-                                               b *= lightp1;\r
-                                       } else if (lightness > 0) {\r
-                                               r = r * lightm1 + light255;\r
-                                               g = g * lightm1 + light255;\r
-                                               b = b * lightm1 + light255;\r
-                                       }\r
-\r
-                                       if (r < 0) r = 0;\r
-                                       if (g < 0) g = 0;\r
-                                       if (b < 0) b = 0;\r
-                                       if (r > 255) r = 255;\r
-                                       if (g > 255) g = 255;\r
-                                       if (b > 255) b = 255;\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-\r
-}\r
-/*\r
- * Pixastic Lib - Invert filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.invert = {\r
-       process : function(params) {\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-\r
-                       var invertAlpha = !!params.options.invertAlpha;\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x-1)*4;\r
-                                       data[offset] = 255 - data[offset];\r
-                                       data[offset+1] = 255 - data[offset+1];\r
-                                       data[offset+2] = 255 - data[offset+2];\r
-                                       if (invertAlpha) data[offset+3] = 255 - data[offset+3];\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       params.image.style.filter += " invert";\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
-       }\r
-}\r
-/*\r
- * Pixastic Lib - Laplace filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.laplace = {\r
-       process : function(params) {\r
-\r
-               var strength = 1.0;\r
-               var invert = !!(params.options.invert && params.options.invert != "false");\r
-               var contrast = parseFloat(params.options.edgeStrength)||0;\r
-\r
-               var greyLevel = parseInt(params.options.greyLevel)||0;\r
-\r
-               contrast = -contrast;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var dataCopy = Pixastic.prepareData(params, true)\r
-\r
-                       var kernel = [\r
-                               [-1,    -1,     -1],\r
-                               [-1,    8,      -1],\r
-                               [-1,    -1,     -1]\r
-                       ];\r
-\r
-                       var weight = 1/8;\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-\r
-                               var nextY = (y == h) ? y - 1 : y;\r
-                               var prevY = (y == 1) ? 0 : y-2;\r
-\r
-                               var offsetYPrev = prevY*w*4;\r
-                               var offsetYNext = nextY*w*4;\r
-\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
-                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
-       \r
-                                       var r = ((-dataCopy[offsetPrev-4]\r
-                                               - dataCopy[offsetPrev]\r
-                                               - dataCopy[offsetPrev+4]\r
-                                               - dataCopy[offset-4]\r
-                                               - dataCopy[offset+4]\r
-                                               - dataCopy[offsetNext-4]\r
-                                               - dataCopy[offsetNext]\r
-                                               - dataCopy[offsetNext+4])\r
-                                               + dataCopy[offset] * 8) \r
-                                               * weight;\r
-       \r
-                                       var g = ((-dataCopy[offsetPrev-3]\r
-                                               - dataCopy[offsetPrev+1]\r
-                                               - dataCopy[offsetPrev+5]\r
-                                               - dataCopy[offset-3]\r
-                                               - dataCopy[offset+5]\r
-                                               - dataCopy[offsetNext-3]\r
-                                               - dataCopy[offsetNext+1]\r
-                                               - dataCopy[offsetNext+5])\r
-                                               + dataCopy[offset+1] * 8)\r
-                                               * weight;\r
-       \r
-                                       var b = ((-dataCopy[offsetPrev-2]\r
-                                               - dataCopy[offsetPrev+2]\r
-                                               - dataCopy[offsetPrev+6]\r
-                                               - dataCopy[offset-2]\r
-                                               - dataCopy[offset+6]\r
-                                               - dataCopy[offsetNext-2]\r
-                                               - dataCopy[offsetNext+2]\r
-                                               - dataCopy[offsetNext+6])\r
-                                               + dataCopy[offset+2] * 8)\r
-                                               * weight;\r
-\r
-                                       var brightness = ((r + g + b)/3) + greyLevel;\r
-\r
-                                       if (contrast != 0) {\r
-                                               if (brightness > 127) {\r
-                                                       brightness += ((brightness + 1) - 128) * contrast;\r
-                                               } else if (brightness < 127) {\r
-                                                       brightness -= (brightness + 1) * contrast;\r
-                                               }\r
-                                       }\r
-                                       if (invert) {\r
-                                               brightness = 255 - brightness;\r
-                                       }\r
-                                       if (brightness < 0 ) brightness = 0;\r
-                                       if (brightness > 255 ) brightness = 255;\r
-\r
-                                       data[offset] = data[offset+1] = data[offset+2] = brightness;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-\r
-/*\r
- * Pixastic Lib - Lighten filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.lighten = {\r
-\r
-       process : function(params) {\r
-               var amount = parseFloat(params.options.amount) || 0;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x-1)*4;\r
-\r
-                                       var r = data[offset];\r
-                                       var g = data[offset+1];\r
-                                       var b = data[offset+2];\r
-\r
-                                       r += r*amount;\r
-                                       g += g*amount;\r
-                                       b += b*amount;\r
-\r
-                                       if (r < 0 ) r = 0;\r
-                                       if (g < 0 ) g = 0;\r
-                                       if (b < 0 ) b = 0;\r
-                                       if (r > 255 ) r = 255;\r
-                                       if (g > 255 ) g = 255;\r
-                                       if (b > 255 ) b = 255;\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-                       return true;\r
-\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       var img = params.image;\r
-                       if (amount < 0) {\r
-                               img.style.filter += " light()";\r
-                               img.filters[img.filters.length-1].addAmbient(\r
-                                       255,255,255,\r
-                                       100 * -amount\r
-                               );\r
-                       } else if (amount > 0) {\r
-                               img.style.filter += " light()";\r
-                               img.filters[img.filters.length-1].addAmbient(\r
-                                       255,255,255,\r
-                                       100\r
-                               );\r
-                               img.filters[img.filters.length-1].addAmbient(\r
-                                       255,255,255,\r
-                                       100 * amount\r
-                               );\r
-                       }\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
-       }\r
-}\r
-/*\r
- * Pixastic Lib - Mosaic filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.mosaic = {\r
-\r
-       process : function(params) {\r
-               var blockSize = Math.max(1,parseInt(params.options.blockSize,10));\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-\r
-                       var ctx = params.canvas.getContext("2d");\r
-\r
-                       var pixel = document.createElement("canvas");\r
-                       pixel.width = pixel.height = 1;\r
-                       var pixelCtx = pixel.getContext("2d");\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = w;\r
-                       copy.height = h;\r
-                       var copyCtx = copy.getContext("2d");\r
-                       copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);\r
-\r
-                       for (var y=0;y<h;y+=blockSize) {\r
-                               for (var x=0;x<w;x+=blockSize) {\r
-                                       var blockSizeX = blockSize;\r
-                                       var blockSizeY = blockSize;\r
-               \r
-                                       if (blockSizeX + x > w)\r
-                                               blockSizeX = w - x;\r
-                                       if (blockSizeY + y > h)\r
-                                               blockSizeY = h - y;\r
-\r
-                                       pixelCtx.drawImage(copy, x, y, blockSizeX, blockSizeY, 0, 0, 1, 1);\r
-                                       var data = pixelCtx.getImageData(0,0,1,1).data;\r
-                                       ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";\r
-                                       ctx.fillRect(rect.left + x, rect.top + y, blockSize, blockSize);\r
-                               }\r
-                       }\r
-                       params.useData = false;\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData());\r
-       }\r
-}/*\r
- * Pixastic Lib - Noise filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.noise = {\r
-\r
-       process : function(params) {\r
-               var amount = 0;\r
-               var strength = 0;\r
-               var mono = false;\r
-\r
-               if (typeof params.options.amount != "undefined")\r
-                       amount = parseFloat(params.options.amount)||0;\r
-               if (typeof params.options.strength != "undefined")\r
-                       strength = parseFloat(params.options.strength)||0;\r
-               if (typeof params.options.mono != "undefined")\r
-                       mono = !!(params.options.mono && params.options.mono != "false");\r
-\r
-               amount = Math.max(0,Math.min(1,amount));\r
-               strength = Math.max(0,Math.min(1,strength));\r
-\r
-               var noise = 128 * strength;\r
-               var noise2 = noise / 2;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       var random = Math.random;\r
-\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x-1)*4;\r
-                                       if (random() < amount) {\r
-                                               if (mono) {\r
-                                                       var pixelNoise = - noise2 + random() * noise;\r
-                                                       var r = data[offset] + pixelNoise;\r
-                                                       var g = data[offset+1] + pixelNoise;\r
-                                                       var b = data[offset+2] + pixelNoise;\r
-                                               } else {\r
-                                                       var r = data[offset] - noise2 + (random() * noise);\r
-                                                       var g = data[offset+1] - noise2 + (random() * noise);\r
-                                                       var b = data[offset+2] - noise2 + (random() * noise);\r
-                                               }\r
-\r
-                                               if (r < 0 ) r = 0;\r
-                                               if (g < 0 ) g = 0;\r
-                                               if (b < 0 ) b = 0;\r
-                                               if (r > 255 ) r = 255;\r
-                                               if (g > 255 ) g = 255;\r
-                                               if (b > 255 ) b = 255;\r
-\r
-                                               data[offset] = r;\r
-                                               data[offset+1] = g;\r
-                                               data[offset+2] = b;\r
-                                       }\r
-                               } while (--x);\r
-                       } while (--y);\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-\r
-/*\r
- * Pixastic Lib - Posterize effect - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.posterize = {\r
-\r
-       process : function(params) {\r
-\r
-               \r
-               var numLevels = 256;\r
-               if (typeof params.options.levels != "undefined")\r
-                       numLevels = parseInt(params.options.levels,10)||1;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-\r
-                       numLevels = Math.max(2,Math.min(256,numLevels));\r
-       \r
-                       var numAreas = 256 / numLevels;\r
-                       var numValues = 256 / (numLevels-1);\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x-1)*4;\r
-\r
-                                       var r = numValues * ((data[offset] / numAreas)>>0);\r
-                                       var g = numValues * ((data[offset+1] / numAreas)>>0);\r
-                                       var b = numValues * ((data[offset+2] / numAreas)>>0);\r
-\r
-                                       if (r > 255) r = 255;\r
-                                       if (g > 255) g = 255;\r
-                                       if (b > 255) b = 255;\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-\r
-\r
-/*\r
- * Pixastic Lib - Pointillize filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.pointillize = {\r
-\r
-       process : function(params) {\r
-               var radius = Math.max(1,parseInt(params.options.radius,10));\r
-               var density = Math.min(5,Math.max(0,parseFloat(params.options.density)||0));\r
-               var noise = Math.max(0,parseFloat(params.options.noise)||0);\r
-               var transparent = !!(params.options.transparent && params.options.transparent != "false");\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-\r
-                       var ctx = params.canvas.getContext("2d");\r
-                       var canvasWidth = params.canvas.width;\r
-                       var canvasHeight = params.canvas.height;\r
-\r
-                       var pixel = document.createElement("canvas");\r
-                       pixel.width = pixel.height = 1;\r
-                       var pixelCtx = pixel.getContext("2d");\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = w;\r
-                       copy.height = h;\r
-                       var copyCtx = copy.getContext("2d");\r
-                       copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);\r
-\r
-                       var diameter = radius * 2;\r
-\r
-                       if (transparent)\r
-                               ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
-\r
-                       var noiseRadius = radius * noise;\r
-\r
-                       var dist = 1 / density;\r
-\r
-                       for (var y=0;y<h+radius;y+=diameter*dist) {\r
-                               for (var x=0;x<w+radius;x+=diameter*dist) {\r
-                                       rndX = noise ? (x+((Math.random()*2-1) * noiseRadius))>>0 : x;\r
-                                       rndY = noise ? (y+((Math.random()*2-1) * noiseRadius))>>0 : y;\r
-\r
-                                       var pixX = rndX - radius;\r
-                                       var pixY = rndY - radius;\r
-                                       if (pixX < 0) pixX = 0;\r
-                                       if (pixY < 0) pixY = 0;\r
-\r
-                                       var cx = rndX + rect.left;\r
-                                       var cy = rndY + rect.top;\r
-                                       if (cx < 0) cx = 0;\r
-                                       if (cx > canvasWidth) cx = canvasWidth;\r
-                                       if (cy < 0) cy = 0;\r
-                                       if (cy > canvasHeight) cy = canvasHeight;\r
-\r
-                                       var diameterX = diameter;\r
-                                       var diameterY = diameter;\r
-\r
-                                       if (diameterX + pixX > w)\r
-                                               diameterX = w - pixX;\r
-                                       if (diameterY + pixY > h)\r
-                                               diameterY = h - pixY;\r
-                                       if (diameterX < 1) diameterX = 1;\r
-                                       if (diameterY < 1) diameterY = 1;\r
-\r
-                                       pixelCtx.drawImage(copy, pixX, pixY, diameterX, diameterY, 0, 0, 1, 1);\r
-                                       var data = pixelCtx.getImageData(0,0,1,1).data;\r
-\r
-                                       ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";\r
-                                       ctx.beginPath();\r
-                                       ctx.arc(cx, cy, radius, 0, Math.PI*2, true);\r
-                                       ctx.closePath();\r
-                                       ctx.fill();\r
-                               }\r
-                       }\r
-\r
-                       params.useData = false;\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData());\r
-       }\r
-}/*\r
- * Pixastic Lib - Resize - v0.1.0\r
- * Copyright (c) 2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.resize = {\r
-       process : function(params) {\r
-               if (Pixastic.Client.hasCanvas()) {\r
-                       var width = parseInt(params.options.width,10);\r
-                       var height = parseInt(params.options.height,10);\r
-                       var canvas = params.canvas;\r
-\r
-                       if (width < 1) width = 1;\r
-                       if (width < 2) width = 2;\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = width;\r
-                       copy.height = height;\r
-\r
-                       copy.getContext("2d").drawImage(canvas,0,0,width,height);\r
-                       canvas.width = width;\r
-                       canvas.height = height;\r
-\r
-                       canvas.getContext("2d").drawImage(copy,0,0);\r
-\r
-                       params.useData = false;\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvas();\r
-       }\r
-}\r
-\r
-\r
-/*\r
- * Pixastic Lib - Remove noise - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.removenoise = {\r
-       process : function(params) {\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-\r
-                               var nextY = (y == h) ? y - 1 : y;\r
-                               var prevY = (y == 1) ? 0 : y-2;\r
-\r
-                               var offsetYPrev = prevY*w*4;\r
-                               var offsetYNext = nextY*w*4;\r
-\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
-                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
-\r
-                                       var minR, maxR, minG, maxG, minB, maxB;\r
-\r
-                                       minR = maxR = data[offsetPrev];\r
-                                       var r1 = data[offset-4], r2 = data[offset+4], r3 = data[offsetNext];\r
-                                       if (r1 < minR) minR = r1;\r
-                                       if (r2 < minR) minR = r2;\r
-                                       if (r3 < minR) minR = r3;\r
-                                       if (r1 > maxR) maxR = r1;\r
-                                       if (r2 > maxR) maxR = r2;\r
-                                       if (r3 > maxR) maxR = r3;\r
-\r
-                                       minG = maxG = data[offsetPrev+1];\r
-                                       var g1 = data[offset-3], g2 = data[offset+5], g3 = data[offsetNext+1];\r
-                                       if (g1 < minG) minG = g1;\r
-                                       if (g2 < minG) minG = g2;\r
-                                       if (g3 < minG) minG = g3;\r
-                                       if (g1 > maxG) maxG = g1;\r
-                                       if (g2 > maxG) maxG = g2;\r
-                                       if (g3 > maxG) maxG = g3;\r
-\r
-                                       minB = maxB = data[offsetPrev+2];\r
-                                       var b1 = data[offset-2], b2 = data[offset+6], b3 = data[offsetNext+2];\r
-                                       if (b1 < minB) minB = b1;\r
-                                       if (b2 < minB) minB = b2;\r
-                                       if (b3 < minB) minB = b3;\r
-                                       if (b1 > maxB) maxB = b1;\r
-                                       if (b2 > maxB) maxB = b2;\r
-                                       if (b3 > maxB) maxB = b3;\r
-\r
-                                       if (data[offset] > maxR) {\r
-                                               data[offset] = maxR;\r
-                                       } else if (data[offset] < minR) {\r
-                                               data[offset] = minR;\r
-                                       }\r
-                                       if (data[offset+1] > maxG) {\r
-                                               data[offset+1] = maxG;\r
-                                       } else if (data[offset+1] < minG) {\r
-                                               data[offset+1] = minG;\r
-                                       }\r
-                                       if (data[offset+2] > maxB) {\r
-                                               data[offset+2] = maxB;\r
-                                       } else if (data[offset+2] < minB) {\r
-                                               data[offset+2] = minB;\r
-                                       }\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}/*\r
- * Pixastic Lib - Rotate - v0.1.0\r
- * Copyright (c) 2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.rotate = {\r
-       process : function(params) {\r
-               if (Pixastic.Client.hasCanvas()) {\r
-                       var canvas = params.canvas;\r
-\r
-                       var width = params.width;\r
-                       var height = params.height;\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = width;\r
-                       copy.height = height;\r
-                       copy.getContext("2d").drawImage(canvas,0,0,width,height);\r
-\r
-                       var angle = -parseFloat(params.options.angle) * Math.PI / 180;\r
-\r
-                       var dimAngle = angle;\r
-                       if (dimAngle > Math.PI*0.5)\r
-                               dimAngle = Math.PI - dimAngle;\r
-                       if (dimAngle < -Math.PI*0.5)\r
-                               dimAngle = -Math.PI - dimAngle;\r
-\r
-                       var diag = Math.sqrt(width*width + height*height);\r
-\r
-                       var diagAngle1 = Math.abs(dimAngle) - Math.abs(Math.atan2(height, width));\r
-                       var diagAngle2 = Math.abs(dimAngle) + Math.abs(Math.atan2(height, width));\r
-\r
-                       var newWidth = Math.abs(Math.cos(diagAngle1) * diag);\r
-                       var newHeight = Math.abs(Math.sin(diagAngle2) * diag);\r
-\r
-                       canvas.width = newWidth;\r
-                       canvas.height = newHeight;\r
-\r
-                       var ctx = canvas.getContext("2d");\r
-                       ctx.translate(newWidth/2, newHeight/2);\r
-                       ctx.rotate(angle);\r
-                       ctx.drawImage(copy,-width/2,-height/2);\r
-\r
-                       params.useData = false;\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvas();\r
-       }\r
-}\r
-\r
-\r
-/*\r
- * Pixastic Lib - Sepia filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.sepia = {\r
-\r
-       process : function(params) {\r
-               var mode = (parseInt(params.options.mode,10)||0);\r
-               if (mode < 0) mode = 0;\r
-               if (mode > 1) mode = 1;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x-1)*4;\r
-\r
-                                       if (mode) {\r
-                                               // a bit faster, but not as good\r
-                                               var d = data[offset] * 0.299 + data[offset+1] * 0.587 + data[offset+2] * 0.114;\r
-                                               var r = (d + 39);\r
-                                               var g = (d + 14);\r
-                                               var b = (d - 36);\r
-                                       } else {\r
-                                               // Microsoft\r
-                                               var or = data[offset];\r
-                                               var og = data[offset+1];\r
-                                               var ob = data[offset+2];\r
-       \r
-                                               var r = (or * 0.393 + og * 0.769 + ob * 0.189);\r
-                                               var g = (or * 0.349 + og * 0.686 + ob * 0.168);\r
-                                               var b = (or * 0.272 + og * 0.534 + ob * 0.131);\r
-                                       }\r
-\r
-                                       if (r < 0) r = 0; if (r > 255) r = 255;\r
-                                       if (g < 0) g = 0; if (g > 255) g = 255;\r
-                                       if (b < 0) b = 0; if (b > 255) b = 255;\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}/*\r
- * Pixastic Lib - Sharpen filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.sharpen = {\r
-       process : function(params) {\r
-\r
-               var strength = 0;\r
-               if (typeof params.options.amount != "undefined")\r
-                       strength = parseFloat(params.options.amount)||0;\r
-\r
-               if (strength < 0) strength = 0;\r
-               if (strength > 1) strength = 1;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var dataCopy = Pixastic.prepareData(params, true)\r
-\r
-                       var mul = 15;\r
-                       var mulOther = 1 + 3*strength;\r
-\r
-                       var kernel = [\r
-                               [0,     -mulOther,      0],\r
-                               [-mulOther,     mul,    -mulOther],\r
-                               [0,     -mulOther,      0]\r
-                       ];\r
-\r
-                       var weight = 0;\r
-                       for (var i=0;i<3;i++) {\r
-                               for (var j=0;j<3;j++) {\r
-                                       weight += kernel[i][j];\r
-                               }\r
-                       }\r
-\r
-                       weight = 1 / weight;\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       mul *= weight;\r
-                       mulOther *= weight;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-\r
-                               var nextY = (y == h) ? y - 1 : y;\r
-                               var prevY = (y == 1) ? 0 : y-2;\r
-\r
-                               var offsetYPrev = prevY*w4;\r
-                               var offsetYNext = nextY*w4;\r
-\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
-                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
-\r
-                                       var r = ((\r
-                                               - dataCopy[offsetPrev]\r
-                                               - dataCopy[offset-4]\r
-                                               - dataCopy[offset+4]\r
-                                               - dataCopy[offsetNext])         * mulOther\r
-                                               + dataCopy[offset]      * mul\r
-                                               );\r
-\r
-                                       var g = ((\r
-                                               - dataCopy[offsetPrev+1]\r
-                                               - dataCopy[offset-3]\r
-                                               - dataCopy[offset+5]\r
-                                               - dataCopy[offsetNext+1])       * mulOther\r
-                                               + dataCopy[offset+1]    * mul\r
-                                               );\r
-\r
-                                       var b = ((\r
-                                               - dataCopy[offsetPrev+2]\r
-                                               - dataCopy[offset-2]\r
-                                               - dataCopy[offset+6]\r
-                                               - dataCopy[offsetNext+2])       * mulOther\r
-                                               + dataCopy[offset+2]    * mul\r
-                                               );\r
-\r
-\r
-                                       if (r < 0 ) r = 0;\r
-                                       if (g < 0 ) g = 0;\r
-                                       if (b < 0 ) b = 0;\r
-                                       if (r > 255 ) r = 255;\r
-                                       if (g > 255 ) g = 255;\r
-                                       if (b > 255 ) b = 255;\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-/*\r
- * Pixastic Lib - Solarize filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.solarize = {\r
-\r
-       process : function(params) {\r
-               var useAverage = !!(params.options.average && params.options.average != "false");\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x-1)*4;\r
-\r
-                                       var r = data[offset];\r
-                                       var g = data[offset+1];\r
-                                       var b = data[offset+2];\r
-\r
-                                       if (r > 127) r = 255 - r;\r
-                                       if (g > 127) g = 255 - g;\r
-                                       if (b > 127) b = 255 - b;\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData());\r
-       }\r
-}/*\r
- * Pixastic Lib - USM - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-\r
-Pixastic.Actions.unsharpmask = {\r
-       process : function(params) {\r
-\r
-               var amount = (parseFloat(params.options.amount)||0);\r
-               var blurAmount = parseFloat(params.options.radius)||0;\r
-               var threshold = parseFloat(params.options.threshold)||0;\r
-\r
-               amount = Math.min(500,Math.max(0,amount)) / 2;\r
-               blurAmount = Math.min(5,Math.max(0,blurAmount)) / 10;\r
-               threshold = Math.min(255,Math.max(0,threshold));\r
-\r
-               threshold--;\r
-               var thresholdNeg = -threshold;\r
-\r
-               amount *= 0.016;\r
-               amount++;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var rect = params.options.rect;\r
-\r
-                       var blurCanvas = document.createElement("canvas");\r
-                       blurCanvas.width = params.width;\r
-                       blurCanvas.height = params.height;\r
-                       var blurCtx = blurCanvas.getContext("2d");\r
-                       blurCtx.drawImage(params.canvas,0,0);\r
-\r
-                       var scale = 2;\r
-                       var smallWidth = Math.round(params.width / scale);\r
-                       var smallHeight = Math.round(params.height / scale);\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = smallWidth;\r
-                       copy.height = smallHeight;\r
-\r
-                       var steps = Math.round(blurAmount * 20);\r
-\r
-                       var copyCtx = copy.getContext("2d");\r
-                       for (var i=0;i<steps;i++) {\r
-                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));\r
-                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));\r
-\r
-                               copyCtx.clearRect(0,0,smallWidth,smallHeight);\r
-\r
-                               copyCtx.drawImage(\r
-                                       blurCanvas,\r
-                                       0,0,params.width,params.height,\r
-                                       0,0,scaledWidth,scaledHeight\r
-                               );\r
-       \r
-                               blurCtx.clearRect(0,0,params.width,params.height);\r
-       \r
-                               blurCtx.drawImage(\r
-                                       copy,\r
-                                       0,0,scaledWidth,scaledHeight,\r
-                                       0,0,params.width,params.height\r
-                               );\r
-                       }\r
-\r
-                       var data = Pixastic.prepareData(params);\r
-                       var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var difR = data[offset] - blurData[offset];\r
-                                       if (difR > threshold || difR < thresholdNeg) {\r
-                                               var blurR = blurData[offset];\r
-                                               blurR = amount * difR + blurR;\r
-                                               data[offset] = blurR > 255 ? 255 : (blurR < 0 ? 0 : blurR);\r
-                                       }\r
-\r
-                                       var difG = data[offset+1] - blurData[offset+1];\r
-                                       if (difG > threshold || difG < thresholdNeg) {\r
-                                               var blurG = blurData[offset+1];\r
-                                               blurG = amount * difG + blurG;\r
-                                               data[offset+1] = blurG > 255 ? 255 : (blurG < 0 ? 0 : blurG);\r
-                                       }\r
-\r
-                                       var difB = data[offset+2] - blurData[offset+2];\r
-                                       if (difB > threshold || difB < thresholdNeg) {\r
-                                               var blurB = blurData[offset+2];\r
-                                               blurB = amount * difB + blurB;\r
-                                               data[offset+2] = blurB > 255 ? 255 : (blurB < 0 ? 0 : blurB);\r
-                                       }\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-\r
-\r
-\r
-\r
+/*
+ * Pixastic Lib - Core Functions - v0.1.3
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+var Pixastic = (function() {
+
+
+       function addEvent(el, event, handler) {
+               if (el.addEventListener)
+                       el.addEventListener(event, handler, false); 
+               else if (el.attachEvent)
+                       el.attachEvent("on" + event, handler); 
+       }
+
+       function onready(handler) {
+               var handlerDone = false;
+               var execHandler = function() {
+                       if (!handlerDone) {
+                               handlerDone = true;
+                               handler();
+                       }
+               }
+               document.write("<"+"script defer src=\"//:\" id=\"__onload_ie_sumbox__\"></"+"script>");
+               var script = document.getElementById("__onload_ie_sumbox__");
+               script.onreadystatechange = function() {
+                       if (script.readyState == "complete") {
+                               script.parentNode.removeChild(script);
+                               execHandler();
+                       }
+               }
+               if (document.addEventListener)
+                       document.addEventListener("DOMContentLoaded", execHandler, false); 
+               addEvent(window, "load", execHandler);
+       }
+
+       function init() {
+               if (!Pixastic.parseOnLoad) return;
+               var imgEls = getElementsByClass("pixastic", null, "img");
+               var canvasEls = getElementsByClass("pixastic", null, "canvas");
+               var elements = imgEls.concat(canvasEls);
+               for (var i=0;i<elements.length;i++) {
+                       (function() {
+
+                       var el = elements[i];
+                       var actions = [];
+                       var classes = el.className.split(" ");
+                       for (var c=0;c<classes.length;c++) {
+                               var cls = classes[c];
+                               if (cls.substring(0,9) == "pixastic-") {
+                                       var actionName = cls.substring(9);
+                                       if (actionName != "")
+                                               actions.push(actionName);
+                               }
+                       }
+                       if (actions.length) {
+                               if (el.tagName.toLowerCase() == "img") {
+                                       var dataImg = new Image();
+                                       dataImg.src = el.src;
+                                       if (dataImg.complete) {
+                                               for (var a=0;a<actions.length;a++) {
+                                                       var res = Pixastic.applyAction(el, el, actions[a], null);
+                                                       if (res) 
+                                                               el = res;
+                                               }
+                                       } else {
+                                               dataImg.onload = function() {
+                                                       for (var a=0;a<actions.length;a++) {
+                                                               var res = Pixastic.applyAction(el, el, actions[a], null)
+                                                               if (res) 
+                                                                       el = res;
+                                                       }
+                                               }
+                                       }
+                               } else {
+                                       setTimeout(function() {
+                                               for (var a=0;a<actions.length;a++) {
+                                                       var res = Pixastic.applyAction(
+                                                               el, el, actions[a], null
+                                                       );
+                                                       if (res) 
+                                                               el = res;
+                                               }
+                                       },1);
+                               }
+                       }
+
+                       })();
+               }
+       }
+
+//     if (typeof pixastic_no_onready == "undefined") // yuck.
+//             onready(init);
+
+       // getElementsByClass by Dustin Diaz, http://www.dustindiaz.com/getelementsbyclass/
+       function getElementsByClass(searchClass,node,tag) {
+               var classElements = new Array();
+               if ( node == null )
+                       node = document;
+               if ( tag == null )
+                       tag = '*';
+
+               var els = node.getElementsByTagName(tag);
+               var elsLen = els.length;
+               var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
+               for (i = 0, j = 0; i < elsLen; i++) {
+                       if ( pattern.test(els[i].className) ) {
+                               classElements[j] = els[i];
+                               j++;
+                       }
+               }
+               return classElements;
+       }
+
+       var debugElement;
+
+       function writeDebug(text, level) {
+               if (!Pixastic.debug) return;
+               try {
+                       switch (level) {
+                               case "warn" : 
+                                       console.warn("Pixastic:", text);
+                                       break;
+                               case "error" :
+                                       console.error("Pixastic:", text);
+                                       break;
+                               default:
+                                       console.log("Pixastic:", text);
+                       }
+               } catch(e) {
+               }
+               if (!debugElement) {
+                       
+               }
+       }
+
+
+       return {
+
+               parseOnLoad : false,
+
+               debug : false,
+               
+               applyAction : function(img, dataImg, actionName, options) {
+
+                       options = options || {};
+
+                       var imageIsCanvas = (img.tagName.toLowerCase() == "canvas");
+                       if (imageIsCanvas && Pixastic.Client.isIE()) {
+                               if (Pixastic.debug) writeDebug("Tried to process a canvas element but browser is IE.");
+                               return false;
+                       }
+
+                       var canvas, ctx;
+                       if (Pixastic.Client.hasCanvas()) {
+                               canvas = document.createElement("canvas");
+                               ctx = canvas.getContext("2d");
+                       }
+
+                       var w = parseInt(img.offsetWidth);
+                       var h = parseInt(img.offsetHeight);
+
+                       if (imageIsCanvas) {
+                               w = img.width;
+                               h = img.height;
+                       }
+
+                       if (actionName.indexOf("(") > -1) {
+                               var tmp = actionName;
+                               actionName = tmp.substr(0, tmp.indexOf("("));
+                               var arg = tmp.match(/\((.*?)\)/);
+                               if (arg[1]) {
+                                       arg = arg[1].split(";");
+                                       for (var a=0;a<arg.length;a++) {
+                                               thisArg = arg[a].split("=");
+                                               if (thisArg.length == 2) {
+                                                       if (thisArg[0] == "rect") {
+                                                               var rectVal = thisArg[1].split(",");
+                                                               options[thisArg[0]] = {
+                                                                       left : parseInt(rectVal[0],10)||0,
+                                                                       top : parseInt(rectVal[1],10)||0,
+                                                                       width : parseInt(rectVal[2],10)||0,
+                                                                       height : parseInt(rectVal[3],10)||0
+                                                               }
+                                                       } else {
+                                                               options[thisArg[0]] = thisArg[1];
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (!options.rect) {
+                               options.rect = {
+                                       left : 0, top : 0, width : w, height : h
+                               };
+                       }
+                       var validAction = false;
+                       if (Pixastic.Actions[actionName] && typeof Pixastic.Actions[actionName].process == "function") {
+                               validAction = true;
+                       }
+                       if (!validAction) {
+                               if (Pixastic.debug) writeDebug("Invalid action \"" + actionName + "\". Maybe file not included?");
+                               return false;
+                       }
+                       if (!Pixastic.Actions[actionName].checkSupport()) {
+                               if (Pixastic.debug) writeDebug("Action \"" + actionName + "\" not supported by this browser.");
+                               return false;
+                       }
+
+                       if (Pixastic.Client.hasCanvas()) {
+                               canvas.width = w;
+                               canvas.height = h;
+                               canvas.style.width = w+"px";
+                               canvas.style.height = h+"px";
+                               ctx.drawImage(dataImg,0,0,w,h);
+
+                               if (!img.__pixastic_org_image) {
+                                       canvas.__pixastic_org_image = img;
+                                       canvas.__pixastic_org_width = w;
+                                       canvas.__pixastic_org_height = h;
+                               } else {
+                                       canvas.__pixastic_org_image = img.__pixastic_org_image;
+                                       canvas.__pixastic_org_width = img.__pixastic_org_width;
+                                       canvas.__pixastic_org_height = img.__pixastic_org_height;
+                               }
+
+                       } else if (Pixastic.Client.isIE() && typeof img.__pixastic_org_style == "undefined") {
+                               img.__pixastic_org_style = img.style.cssText;
+                       }
+
+                       var params = {
+                               image : img,
+                               canvas : canvas,
+                               width : w,
+                               height : h,
+                               useData : true,
+                               options : options
+                       }
+
+                       // Ok, let's do it!
+
+                       var res = Pixastic.Actions[actionName].process(params);
+
+                       if (!res) {
+                               return false;
+                       }
+
+                       if (Pixastic.Client.hasCanvas()) {
+                               if (params.useData) {
+                                       if (Pixastic.Client.hasCanvasImageData()) {
+                                               canvas.getContext("2d").putImageData(params.canvasData, options.rect.left, options.rect.top);
+
+                                               // Opera doesn't seem to update the canvas until we draw something on it, lets draw a 0x0 rectangle.
+                                               canvas.getContext("2d").fillRect(0,0,0,0);
+                                       }
+                               }
+
+                               if (!options.leaveDOM) {
+                                       // copy properties and stuff from the source image
+                                       canvas.title = img.title;
+                                       canvas.imgsrc = img.imgsrc;
+                                       if (!imageIsCanvas) canvas.alt  = img.alt;
+                                       if (!imageIsCanvas) canvas.imgsrc = img.src;
+                                       canvas.className = img.className;
+                                       canvas.style.cssText = img.style.cssText;
+                                       canvas.name = img.name;
+                                       canvas.tabIndex = img.tabIndex;
+                                       canvas.id = img.id;
+                                       if (img.parentNode && img.parentNode.replaceChild) {
+                                               img.parentNode.replaceChild(canvas, img);
+                                       }
+                               }
+
+                               options.resultCanvas = canvas;
+
+                               return canvas;
+                       }
+
+                       return img;
+               },
+
+               prepareData : function(params, getCopy) {
+                       var ctx = params.canvas.getContext("2d");
+                       var rect = params.options.rect;
+                       var dataDesc = ctx.getImageData(rect.left, rect.top, rect.width, rect.height);
+                       var data = dataDesc.data;
+                       if (!getCopy) params.canvasData = dataDesc;
+                       return data;
+               },
+
+               // load the image file
+               process : function(img, actionName, options, callback)
+               {
+                       if (img.tagName.toLowerCase() == "img") {
+                               var dataImg = new Image();
+                               dataImg.src = img.src;
+                               if (dataImg.complete) {
+                                       var res = Pixastic.applyAction(img, dataImg, actionName, options);
+                                       if (callback) callback(res);
+                                       return res;
+                               } else {
+                                       dataImg.onload = function() {
+                                               var res = Pixastic.applyAction(img, dataImg, actionName, options)
+                                               if (callback) callback(res);
+                                       }
+                               }
+                       }
+                       if (img.tagName.toLowerCase() == "canvas") {
+                               var res = Pixastic.applyAction(img, img, actionName, options);
+                               if (callback) callback(res);
+                               return res;
+                       }
+               },
+
+               revert : function(img) {
+                       if (Pixastic.Client.hasCanvas()) {
+                               if (img.tagName.toLowerCase() == "canvas" && img.__pixastic_org_image) {
+                                       img.width = img.__pixastic_org_width;
+                                       img.height = img.__pixastic_org_height;
+                                       img.getContext("2d").drawImage(img.__pixastic_org_image, 0, 0);
+
+                                       if (img.parentNode && img.parentNode.replaceChild) {
+                                               img.parentNode.replaceChild(img.__pixastic_org_image, img);
+                                       }
+
+                                       return img;
+                               }
+                       } else if (Pixastic.Client.isIE() && typeof img.__pixastic_org_style != "undefined") {
+                               img.style.cssText = img.__pixastic_org_style;
+                       }
+               },
+
+               Client : {
+                       hasCanvas : (function() {
+                               var c = document.createElement("canvas");
+                               var val = false;
+                               try {
+                                       val = !!((typeof c.getContext == "function") && c.getContext("2d"));
+                               } catch(e) {}
+                               return function() {
+                                       return val;
+                               }
+                       })(),
+
+                       hasCanvasImageData : (function() {
+                               var c = document.createElement("canvas");
+                               var val = false;
+                               var ctx;
+                               try {
+                                       if (typeof c.getContext == "function" && (ctx = c.getContext("2d"))) {
+                                               val = (typeof ctx.getImageData == "function");
+                                       }
+                               } catch(e) {}
+                               return function() {
+                                       return val;
+                               }
+                       })(),
+
+                       isIE : function() {
+                               return !!document.all && !!window.attachEvent && !window.opera;
+                       }
+               },
+
+               Actions : {}
+       }
+
+
+})();
+/*
+ * Pixastic Lib - jQuery plugin
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+if (typeof jQuery != "undefined" && jQuery && jQuery.fn) {
+       jQuery.fn.pixastic = function(action, options) {
+               var newElements = [];
+               this.each(
+                       function () {
+                               if (this.tagName.toLowerCase() == "img" && !this.complete) {
+                                       return;
+                               }
+                               var res = Pixastic.process(this, action, options);
+                               if (res) {
+                                       newElements.push(res);
+                               }
+                       }
+               );
+               if (newElements.length > 0)
+                       return jQuery(newElements);
+               else
+                       return this;
+       };
+
+};
+/*
+ * Pixastic Lib - Blend - v0.1.1
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.blend = {
+
+       process : function(params) {
+               var amount = parseFloat(params.options.amount);
+               var mode = (params.options.mode || "normal").toLowerCase();
+               var image = params.options.image;
+
+               amount = Math.max(0,Math.min(1,amount));
+
+               if (!image) return false;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var rect = params.options.rect;
+                       var data = Pixastic.prepareData(params);
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       params.useData = false;
+
+                       var otherCanvas = document.createElement("canvas");
+                       otherCanvas.width = params.canvas.width;
+                       otherCanvas.height = params.canvas.height;
+                       var otherCtx = otherCanvas.getContext("2d");
+                       otherCtx.drawImage(image,0,0);
+
+                       var params2 = {canvas:otherCanvas,options:params.options};
+                       var data2 = Pixastic.prepareData(params2);
+                       var dataDesc2 = params2.canvasData;
+
+                       var p = w*h;
+                       var pix = p*4;
+                       var pix1, pix2;
+                       var r1, g1, b1;
+                       var r2, g2, b2;
+                       var r3, g3, b3;
+                       var r4, g4, b4;
+
+                       var dataChanged = false;
+
+                       switch (mode) {
+                               case "normal" : 
+                                       //while (p--) {
+                                       //      data2[pix-=4] = data2[pix];
+                                       //      data2[pix1=pix+1] = data2[pix1];
+                                       //      data2[pix2=pix+2] = data2[pix2];
+                                       //}
+                                       break;
+
+                               case "multiply" : 
+                                       while (p--) {
+                                               data2[pix-=4] = data[pix] * data2[pix] / 255;
+                                               data2[pix1=pix+1] = data[pix1] * data2[pix1] / 255;
+                                               data2[pix2=pix+2] = data[pix2] * data2[pix2] / 255;
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "lighten" : 
+                                       while (p--) {
+                                               if ((r1 = data[pix-=4]) > data2[pix])
+                                                       data2[pix] = r1;
+                                               if ((g1 = data[pix1=pix+1]) > data2[pix1])
+                                                       data2[pix1] = g1;
+                                               if ((b1 = data[pix2=pix+2]) > data2[pix2])
+                                                       data2[pix2] = b1;
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "darken" : 
+                                       while (p--) {
+                                               if ((r1 = data[pix-=4]) < data2[pix])
+                                                       data2[pix] = r1;
+                                               if ((g1 = data[pix1=pix+1]) < data2[pix1])
+                                                       data2[pix1] = g1;
+                                               if ((b1 = data[pix2=pix+2]) < data2[pix2])
+                                                       data2[pix2] = b1;
+
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "darkercolor" : 
+                                       while (p--) {
+                                               if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) <= (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {
+                                                       data2[pix] = r1;
+                                                       data2[pix1] = g1;
+                                                       data2[pix2] = b1;
+                                               }
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "lightercolor" : 
+                                       while (p--) {
+                                               if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) > (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {
+                                                       data2[pix] = r1;
+                                                       data2[pix1] = g1;
+                                                       data2[pix2] = b1;
+                                               }
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "lineardodge" : 
+                                       otherCtx.globalCompositeOperation = "source-over";
+                                       otherCtx.drawImage(params.canvas, 0, 0);
+                                       otherCtx.globalCompositeOperation = "lighter";
+                                       otherCtx.drawImage(image, 0, 0);
+
+                                       /*
+                                       while (p--) {
+                                               if ((r3 = data[pix-=4] + data2[pix]) > 255)
+                                                       data2[pix] = 255;
+                                               else
+                                                       data2[pix] = r3;
+                                               if ((g3 = data[pix1=pix+1] + data2[pix1]) > 255)
+                                                       data2[pix1] = 255;
+                                               else
+                                                       data2[pix1] = g3;
+                                               if ((b3 = data[pix2=pix+2] + data2[pix2]) > 255)
+                                                       data2[pix2] = 255;
+                                               else
+                                                       data2[pix2] = b3;
+                                       }
+                                       dataChanged = true;
+                                       */
+
+                                       break;
+
+                               case "linearburn" : 
+                                       while (p--) {
+                                               if ((r3 = data[pix-=4] + data2[pix]) < 255)
+                                                       data2[pix] = 0;
+                                               else
+                                                       data2[pix] = (r3 - 255);
+                                               if ((g3 = data[pix1=pix+1] + data2[pix1]) < 255)
+                                                       data2[pix1] = 0;
+                                               else
+                                                       data2[pix1] = (g3 - 255);
+                                               if ((b3 = data[pix2=pix+2] + data2[pix2]) < 255)
+                                                       data2[pix2] = 0;
+                                               else
+                                                       data2[pix2] = (b3 - 255);
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "difference" : 
+                                       while (p--) {
+                                               if ((r3 = data[pix-=4] - data2[pix]) < 0)
+                                                       data2[pix] = -r3;
+                                               else
+                                                       data2[pix] = r3;
+                                               if ((g3 = data[pix1=pix+1] - data2[pix1]) < 0)
+                                                       data2[pix1] = -g3;
+                                               else
+                                                       data2[pix1] = g3;
+                                               if ((b3 = data[pix2=pix+2] - data2[pix2]) < 0)
+                                                       data2[pix2] = -b3;
+                                               else
+                                                       data2[pix2] = b3;
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "screen" : 
+                                       while (p--) {
+                                               data2[pix-=4] = (255 - ( ((255-data2[pix])*(255-data[pix])) >> 8));
+                                               data2[pix1=pix+1] = (255 - ( ((255-data2[pix1])*(255-data[pix1])) >> 8));
+                                               data2[pix2=pix+2] = (255 - ( ((255-data2[pix2])*(255-data[pix2])) >> 8));
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "exclusion" : 
+                                       var div_2_255 = 2 / 255;
+                                       while (p--) {
+                                               data2[pix-=4] = (r1 = data[pix]) - (r1 * div_2_255 - 1) * data2[pix];
+                                               data2[pix1=pix+1] = (g1 = data[pix1]) - (g1 * div_2_255 - 1) * data2[pix1];
+                                               data2[pix2=pix+2] = (b1 = data[pix2]) - (b1 * div_2_255 - 1) * data2[pix2];
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "overlay" : 
+                                       var div_2_255 = 2 / 255;
+                                       while (p--) {
+                                               if ((r1 = data[pix-=4]) < 128)
+                                                       data2[pix] = data2[pix]*r1*div_2_255;
+                                               else
+                                                       data2[pix] = 255 - (255-data2[pix])*(255-r1)*div_2_255;
+
+                                               if ((g1 = data[pix1=pix+1]) < 128)
+                                                       data2[pix1] = data2[pix1]*g1*div_2_255;
+                                               else
+                                                       data2[pix1] = 255 - (255-data2[pix1])*(255-g1)*div_2_255;
+
+                                               if ((b1 = data[pix2=pix+2]) < 128)
+                                                       data2[pix2] = data2[pix2]*b1*div_2_255;
+                                               else
+                                                       data2[pix2] = 255 - (255-data2[pix2])*(255-b1)*div_2_255;
+
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "softlight" : 
+                                       var div_2_255 = 2 / 255;
+                                       while (p--) {
+                                               if ((r1 = data[pix-=4]) < 128)
+                                                       data2[pix] = ((data2[pix]>>1) + 64) * r1 * div_2_255;
+                                               else
+                                                       data2[pix] = 255 - (191 - (data2[pix]>>1)) * (255-r1) * div_2_255;
+
+                                               if ((g1 = data[pix1=pix+1]) < 128)
+                                                       data2[pix1] = ((data2[pix1]>>1)+64) * g1 * div_2_255;
+                                               else
+                                                       data2[pix1] = 255 - (191 - (data2[pix1]>>1)) * (255-g1) * div_2_255;
+
+                                               if ((b1 = data[pix2=pix+2]) < 128)
+                                                       data2[pix2] = ((data2[pix2]>>1)+64) * b1 * div_2_255;
+                                               else
+                                                       data2[pix2] = 255 - (191 - (data2[pix2]>>1)) * (255-b1) * div_2_255;
+
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "hardlight" : 
+                                       var div_2_255 = 2 / 255;
+                                       while (p--) {
+                                               if ((r2 = data2[pix-=4]) < 128)
+                                                       data2[pix] = data[pix] * r2 * div_2_255;
+                                               else
+                                                       data2[pix] = 255 - (255-data[pix]) * (255-r2) * div_2_255;
+
+                                               if ((g2 = data2[pix1=pix+1]) < 128)
+                                                       data2[pix1] = data[pix1] * g2 * div_2_255;
+                                               else
+                                                       data2[pix1] = 255 - (255-data[pix1]) * (255-g2) * div_2_255;
+
+                                               if ((b2 = data2[pix2=pix+2]) < 128)
+                                                       data2[pix2] = data[pix2] * b2 * div_2_255;
+                                               else
+                                                       data2[pix2] = 255 - (255-data[pix2]) * (255-b2) * div_2_255;
+
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "colordodge" : 
+                                       while (p--) {
+                                               if ((r3 = (data[pix-=4]<<8)/(255-(r2 = data2[pix]))) > 255 || r2 == 255)
+                                                       data2[pix] = 255;
+                                               else
+                                                       data2[pix] = r3;
+
+                                               if ((g3 = (data[pix1=pix+1]<<8)/(255-(g2 = data2[pix1]))) > 255 || g2 == 255)
+                                                       data2[pix1] = 255;
+                                               else
+                                                       data2[pix1] = g3;
+
+                                               if ((b3 = (data[pix2=pix+2]<<8)/(255-(b2 = data2[pix2]))) > 255 || b2 == 255)
+                                                       data2[pix2] = 255;
+                                               else
+                                                       data2[pix2] = b3;
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "colorburn" : 
+                                       while (p--) {
+                                               if ((r3 = 255-((255-data[pix-=4])<<8)/data2[pix]) < 0 || data2[pix] == 0)
+                                                       data2[pix] = 0;
+                                               else
+                                                       data2[pix] = r3;
+
+                                               if ((g3 = 255-((255-data[pix1=pix+1])<<8)/data2[pix1]) < 0 || data2[pix1] == 0)
+                                                       data2[pix1] = 0;
+                                               else
+                                                       data2[pix1] = g3;
+
+                                               if ((b3 = 255-((255-data[pix2=pix+2])<<8)/data2[pix2]) < 0 || data2[pix2] == 0)
+                                                       data2[pix2] = 0;
+                                               else
+                                                       data2[pix2] = b3;
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "linearlight" : 
+                                       while (p--) {
+                                               if ( ((r3 = 2*(r2=data2[pix-=4])+data[pix]-256) < 0) || (r2 < 128 && r3 < 0)) {
+                                                       data2[pix] = 0
+                                               } else {
+                                                       if (r3 > 255)
+                                                               data2[pix] = 255;
+                                                       else
+                                                               data2[pix] = r3;
+                                               }
+                                               if ( ((g3 = 2*(g2=data2[pix1=pix+1])+data[pix1]-256) < 0) || (g2 < 128 && g3 < 0)) {
+                                                       data2[pix1] = 0
+                                               } else {
+                                                       if (g3 > 255)
+                                                               data2[pix1] = 255;
+                                                       else
+                                                               data2[pix1] = g3;
+                                               }
+                                               if ( ((b3 = 2*(b2=data2[pix2=pix+2])+data[pix2]-256) < 0) || (b2 < 128 && b3 < 0)) {
+                                                       data2[pix2] = 0
+                                               } else {
+                                                       if (b3 > 255)
+                                                               data2[pix2] = 255;
+                                                       else
+                                                               data2[pix2] = b3;
+                                               }
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "vividlight" : 
+                                       while (p--) {
+                                               if ((r2=data2[pix-=4]) < 128) {
+                                                       if (r2) {
+                                                               if ((r3 = 255 - ((255-data[pix])<<8) / (2*r2)) < 0) 
+                                                                       data2[pix] = 0;
+                                                               else
+                                                                       data2[pix] = r3
+                                                       } else {
+                                                               data2[pix] = 0;
+                                                       }
+                                               } else if ((r3 = (r4=2*r2-256)) < 255) {
+                                                       if ((r3 = (data[pix]<<8)/(255-r4)) > 255) 
+                                                               data2[pix] = 255;
+                                                       else
+                                                               data2[pix] = r3;
+                                               } else {
+                                                       if (r3 < 0) 
+                                                               data2[pix] = 0;
+                                                       else
+                                                               data2[pix] = r3
+                                               }
+
+                                               if ((g2=data2[pix1=pix+1]) < 128) {
+                                                       if (g2) {
+                                                               if ((g3 = 255 - ((255-data[pix1])<<8) / (2*g2)) < 0) 
+                                                                       data2[pix1] = 0;
+                                                               else
+                                                                       data2[pix1] = g3;
+                                                       } else {
+                                                               data2[pix1] = 0;
+                                                       }
+                                               } else if ((g3 = (g4=2*g2-256)) < 255) {
+                                                       if ((g3 = (data[pix1]<<8)/(255-g4)) > 255)
+                                                               data2[pix1] = 255;
+                                                       else
+                                                               data2[pix1] = g3;
+                                               } else {
+                                                       if (g3 < 0) 
+                                                               data2[pix1] = 0;
+                                                       else
+                                                               data2[pix1] = g3;
+                                               }
+
+                                               if ((b2=data2[pix2=pix+2]) < 128) {
+                                                       if (b2) {
+                                                               if ((b3 = 255 - ((255-data[pix2])<<8) / (2*b2)) < 0) 
+                                                                       data2[pix2] = 0;
+                                                               else
+                                                                       data2[pix2] = b3;
+                                                       } else {
+                                                               data2[pix2] = 0;
+                                                       }
+                                               } else if ((b3 = (b4=2*b2-256)) < 255) {
+                                                       if ((b3 = (data[pix2]<<8)/(255-b4)) > 255) 
+                                                               data2[pix2] = 255;
+                                                       else
+                                                               data2[pix2] = b3;
+                                               } else {
+                                                       if (b3 < 0) 
+                                                               data2[pix2] = 0;
+                                                       else
+                                                               data2[pix2] = b3;
+                                               }
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "pinlight" : 
+                                       while (p--) {
+                                               if ((r2=data2[pix-=4]) < 128)
+                                                       if ((r1=data[pix]) < (r4=2*r2))
+                                                               data2[pix] = r1;
+                                                       else
+                                                               data2[pix] = r4;
+                                               else
+                                                       if ((r1=data[pix]) > (r4=2*r2-256))
+                                                               data2[pix] = r1;
+                                                       else
+                                                               data2[pix] = r4;
+
+                                               if ((g2=data2[pix1=pix+1]) < 128)
+                                                       if ((g1=data[pix1]) < (g4=2*g2))
+                                                               data2[pix1] = g1;
+                                                       else
+                                                               data2[pix1] = g4;
+                                               else
+                                                       if ((g1=data[pix1]) > (g4=2*g2-256))
+                                                               data2[pix1] = g1;
+                                                       else
+                                                               data2[pix1] = g4;
+
+                                               if ((r2=data2[pix2=pix+2]) < 128)
+                                                       if ((r1=data[pix2]) < (r4=2*r2))
+                                                               data2[pix2] = r1;
+                                                       else
+                                                               data2[pix2] = r4;
+                                               else
+                                                       if ((r1=data[pix2]) > (r4=2*r2-256))
+                                                               data2[pix2] = r1;
+                                                       else
+                                                               data2[pix2] = r4;
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "hardmix" : 
+                                       while (p--) {
+                                               if ((r2 = data2[pix-=4]) < 128)
+                                                       if (255 - ((255-data[pix])<<8)/(2*r2) < 128 || r2 == 0)
+                                                               data2[pix] = 0;
+                                                       else
+                                                               data2[pix] = 255;
+                                               else if ((r4=2*r2-256) < 255 && (data[pix]<<8)/(255-r4) < 128)
+                                                       data2[pix] = 0;
+                                               else
+                                                       data2[pix] = 255;
+
+                                               if ((g2 = data2[pix1=pix+1]) < 128)
+                                                       if (255 - ((255-data[pix1])<<8)/(2*g2) < 128 || g2 == 0)
+                                                               data2[pix1] = 0;
+                                                       else
+                                                               data2[pix1] = 255;
+                                               else if ((g4=2*g2-256) < 255 && (data[pix1]<<8)/(255-g4) < 128)
+                                                       data2[pix1] = 0;
+                                               else
+                                                       data2[pix1] = 255;
+
+                                               if ((b2 = data2[pix2=pix+2]) < 128)
+                                                       if (255 - ((255-data[pix2])<<8)/(2*b2) < 128 || b2 == 0)
+                                                               data2[pix2] = 0;
+                                                       else
+                                                               data2[pix2] = 255;
+                                               else if ((b4=2*b2-256) < 255 && (data[pix2]<<8)/(255-b4) < 128)
+                                                       data2[pix2] = 0;
+                                               else
+                                                       data2[pix2] = 255;
+                                       }
+                                       dataChanged = true;
+                                       break;
+                       }
+
+                       if (dataChanged) 
+                               otherCtx.putImageData(dataDesc2,0,0);
+
+                       var ctx = params.canvas.getContext("2d");
+                       ctx.save();
+                       ctx.globalAlpha = amount;
+                       ctx.drawImage(
+                               otherCanvas,
+                               0,0,rect.width,rect.height,
+                               rect.left,rect.top,rect.width,rect.height
+                       );
+                       ctx.globalAlpha = 1;
+                       ctx.restore();
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}/*
+ * Pixastic Lib - Blur filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.blur = {
+       process : function(params) {
+
+               if (typeof params.options.fixMargin == "undefined")
+                       params.options.fixMargin = true;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       /*
+                       var kernel = [
+                               [0.5,   1,      0.5],
+                               [1,     2,      1],
+                               [0.5,   1,      0.5]
+                       ];
+                       */
+
+                       var kernel = [
+                               [0,     1,      0],
+                               [1,     2,      1],
+                               [0,     1,      0]
+                       ];
+
+                       var weight = 0;
+                       for (var i=0;i<3;i++) {
+                               for (var j=0;j<3;j++) {
+                                       weight += kernel[i][j];
+                               }
+                       }
+
+                       weight = 1 / (weight*2);
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var prevY = (y == 1) ? 0 : y-2;
+                               var nextY = (y == h) ? y - 1 : y;
+
+                               var offsetYPrev = prevY*w*4;
+                               var offsetYNext = nextY*w*4;
+
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
+       
+                                       data[offset] = (
+                                               /*
+                                               dataCopy[offsetPrev - 4]
+                                               + dataCopy[offsetPrev+4] 
+                                               + dataCopy[offsetNext - 4]
+                                               + dataCopy[offsetNext+4]
+                                               + 
+                                               */
+                                               (dataCopy[offsetPrev]
+                                               + dataCopy[offset-4]
+                                               + dataCopy[offset+4]
+                                               + dataCopy[offsetNext])         * 2
+                                               + dataCopy[offset]              * 4
+                                               ) * weight;
+
+                                       data[offset+1] = (
+                                               /*
+                                               dataCopy[offsetPrev - 3]
+                                               + dataCopy[offsetPrev+5] 
+                                               + dataCopy[offsetNext - 3] 
+                                               + dataCopy[offsetNext+5]
+                                               + 
+                                               */
+                                               (dataCopy[offsetPrev+1]
+                                               + dataCopy[offset-3]
+                                               + dataCopy[offset+5]
+                                               + dataCopy[offsetNext+1])       * 2
+                                               + dataCopy[offset+1]            * 4
+                                               ) * weight;
+
+                                       data[offset+2] = (
+                                               /*
+                                               dataCopy[offsetPrev - 2] 
+                                               + dataCopy[offsetPrev+6] 
+                                               + dataCopy[offsetNext - 2] 
+                                               + dataCopy[offsetNext+6]
+                                               + 
+                                               */
+                                               (dataCopy[offsetPrev+2]
+                                               + dataCopy[offset-2]
+                                               + dataCopy[offset+6]
+                                               + dataCopy[offsetNext+2])       * 2
+                                               + dataCopy[offset+2]            * 4
+                                               ) * weight;
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=1.5)";
+
+                       if (params.options.fixMargin) {
+                               params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - 2 + "px";
+                               params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - 2 + "px";
+                       }
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
+       }
+}/*
+ * Pixastic Lib - Blur Fast - v0.1.1
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.blurfast = {
+       process : function(params) {
+
+               var amount = parseFloat(params.options.amount)||0;
+               var clear = !!(params.options.clear && params.options.clear != "false");
+
+               amount = Math.max(0,Math.min(5,amount));
+
+               if (Pixastic.Client.hasCanvas()) {
+                       var rect = params.options.rect;
+
+                       var ctx = params.canvas.getContext("2d");
+                       ctx.save();
+                       ctx.beginPath();
+                       ctx.rect(rect.left, rect.top, rect.width, rect.height);
+                       ctx.clip();
+
+                       var scale = 2;
+                       var smallWidth = Math.round(params.width / scale);
+                       var smallHeight = Math.round(params.height / scale);
+
+                       var copy = document.createElement("canvas");
+                       copy.width = smallWidth;
+                       copy.height = smallHeight;
+
+                       var clear = false;
+                       var steps = Math.round(amount * 20);
+
+                       var copyCtx = copy.getContext("2d");
+                       for (var i=0;i<steps;i++) {
+                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));
+                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));
+       
+                               copyCtx.clearRect(0,0,smallWidth,smallHeight);
+       
+                               copyCtx.drawImage(
+                                       params.canvas,
+                                       0,0,params.width,params.height,
+                                       0,0,scaledWidth,scaledHeight
+                               );
+       
+                               if (clear)
+                                       ctx.clearRect(rect.left,rect.top,rect.width,rect.height);
+       
+                               ctx.drawImage(
+                                       copy,
+                                       0,0,scaledWidth,scaledHeight,
+                                       0,0,params.width,params.height
+                               );
+                       }
+
+                       ctx.restore();
+
+                       params.useData = false;
+                       return true;
+               } else if (Pixastic.Client.isIE()) {
+                       var radius = 10 * amount;
+                       params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=" + radius + ")";
+
+                       if (params.options.fixMargin || 1) {
+                               params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - Math.round(radius) + "px";
+                               params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - Math.round(radius) + "px";
+                       }
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());
+       }
+}
+/*
+ * Pixastic Lib - Brightness/Contrast filter - v0.1.1
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.brightness = {
+
+       process : function(params) {
+
+               var brightness = parseInt(params.options.brightness,10) || 0;
+               var contrast = parseFloat(params.options.contrast)||0;
+               var legacy = !!(params.options.legacy && params.options.legacy != "false");
+
+               if (legacy) {
+                       brightness = Math.min(150,Math.max(-150,brightness));
+               } else {
+                       var brightMul = 1 + Math.min(150,Math.max(-150,brightness)) / 150;
+               }
+               contrast = Math.max(0,contrast+1);
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var p = w*h;
+                       var pix = p*4, pix1, pix2;
+
+                       var mul, add;
+                       if (contrast != 1) {
+                               if (legacy) {
+                                       mul = contrast;
+                                       add = (brightness - 128) * contrast + 128;
+                               } else {
+                                       mul = brightMul * contrast;
+                                       add = - contrast * 128 + 128;
+                               }
+                       } else {  // this if-then is not necessary anymore, is it?
+                               if (legacy) {
+                                       mul = 1;
+                                       add = brightness;
+                               } else {
+                                       mul = brightMul;
+                                       add = 0;
+                               }
+                       }
+                       var r, g, b;
+                       while (p--) {
+                               if ((r = data[pix-=4] * mul + add) > 255 )
+                                       data[pix] = 255;
+                               else if (r < 0)
+                                       data[pix] = 0;
+                               else
+                                       data[pix] = r;
+
+                               if ((g = data[pix1=pix+1] * mul + add) > 255 ) 
+                                       data[pix1] = 255;
+                               else if (g < 0)
+                                       data[pix1] = 0;
+                               else
+                                       data[pix1] = g;
+
+                               if ((b = data[pix2=pix+2] * mul + add) > 255 ) 
+                                       data[pix2] = 255;
+                               else if (b < 0)
+                                       data[pix2] = 0;
+                               else
+                                       data[pix2] = b;
+                       }
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
+/*
+ * Pixastic Lib - Color adjust filter - v0.1.1
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.coloradjust = {
+
+       process : function(params) {
+               var red = parseFloat(params.options.red) || 0;
+               var green = parseFloat(params.options.green) || 0;
+               var blue = parseFloat(params.options.blue) || 0;
+
+               red = Math.round(red*255);
+               green = Math.round(green*255);
+               blue = Math.round(blue*255);
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+
+                       var p = rect.width*rect.height;
+                       var pix = p*4, pix1, pix2;
+
+                       var r, g, b;
+                       while (p--) {
+                               pix -= 4;
+
+                               if (red) {
+                                       if ((r = data[pix] + red) < 0 ) 
+                                               data[pix] = 0;
+                                       else if (r > 255 ) 
+                                               data[pix] = 255;
+                                       else
+                                               data[pix] = r;
+                               }
+
+                               if (green) {
+                                       if ((g = data[pix1=pix+1] + green) < 0 ) 
+                                               data[pix1] = 0;
+                                       else if (g > 255 ) 
+                                               data[pix1] = 255;
+                                       else
+                                               data[pix1] = g;
+                               }
+
+                               if (blue) {
+                                       if ((b = data[pix2=pix+2] + blue) < 0 ) 
+                                               data[pix2] = 0;
+                                       else if (b > 255 ) 
+                                               data[pix2] = 255;
+                                       else
+                                               data[pix2] = b;
+                               }
+                       }
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData());
+       }
+}
+/*
+ * Pixastic Lib - Histogram - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+
+Pixastic.Actions.colorhistogram = {
+
+       array256 : function(default_value) {
+               arr = [];
+               for (var i=0; i<256; i++) { arr[i] = default_value; }
+               return arr
+       },
+       process : function(params) {
+               var values = [];
+               if (typeof params.options.returnValue != "object") {
+                       params.options.returnValue = {rvals:[], gvals:[], bvals:[]};
+               }
+               var paint = !!(params.options.paint);
+
+               var returnValue = params.options.returnValue;
+               if (typeof returnValue.values != "array") {
+                       returnValue.rvals = [];
+                       returnValue.gvals = [];
+                       returnValue.bvals = [];
+               }
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       params.useData = false;
+                       var rvals = this.array256(0);
+                       var gvals = this.array256(0);
+                       var bvals = this.array256(0);
+                       var rect = params.options.rect;
+
+                       var p = rect.width*rect.height;
+                       var pix = p*4;
+                       while (p--) {
+                               rvals[data[pix-=4]]++;
+                               gvals[data[pix+1]]++;
+                               bvals[data[pix+2]]++;
+                       }
+                       returnValue.rvals = rvals;
+                       returnValue.gvals = gvals;
+                       returnValue.bvals = bvals;
+
+                       if (paint) {
+                               var ctx = params.canvas.getContext("2d");
+                               var vals = [rvals, gvals, bvals];
+                               for (var v=0;v<3;v++) {
+                                       var yoff = (v+1) * params.height / 3;
+                                       var maxValue = 0;
+                                       for (var i=0;i<256;i++) {
+                                               if (vals[v][i] > maxValue)
+                                                       maxValue = vals[v][i];
+                                       }
+                                       var heightScale = params.height / 3 / maxValue;
+                                       var widthScale = params.width / 256;
+                                       if (v==0) ctx.fillStyle = "rgba(255,0,0,0.5)";
+                                       else if (v==1) ctx.fillStyle = "rgba(0,255,0,0.5)";
+                                       else if (v==2) ctx.fillStyle = "rgba(0,0,255,0.5)";
+                                       for (var i=0;i<256;i++) {
+                                               ctx.fillRect(
+                                                       i * widthScale, params.height - heightScale * vals[v][i] - params.height + yoff,
+                                                       widthScale, vals[v][i] * heightScale
+                                               );
+                                       }
+                               }
+                       }
+                       return true;
+               }
+       },
+
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}/*
+ * Pixastic Lib - Crop - v0.1.1
+ * Copyright (c) 2008-2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.crop = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvas()) {
+                       var rect = params.options.rect;
+
+                       var width = rect.width;
+                       var height = rect.height;
+                       var top = rect.top;
+                       var left = rect.left;
+
+                       if (typeof params.options.left != "undefined")
+                               left = parseInt(params.options.left,10);
+                       if (typeof params.options.top != "undefined")
+                               top = parseInt(params.options.top,10);
+                       if (typeof params.options.height != "undefined")
+                               width = parseInt(params.options.width,10);
+                       if (typeof params.options.height != "undefined")
+                               height = parseInt(params.options.height,10);
+
+                       if (left < 0) left = 0;
+                       if (left > params.width-1) left = params.width-1;
+
+                       if (top < 0) top = 0;
+                       if (top > params.height-1) top = params.height-1;
+
+                       if (width < 1) width = 1;
+                       if (left + width > params.width)
+                               width = params.width - left;
+
+                       if (height < 1) height = 1;
+                       if (top + height > params.height)
+                               height = params.height - top;
+
+                       var copy = document.createElement("canvas");
+                       copy.width = params.width;
+                       copy.height = params.height;
+                       copy.getContext("2d").drawImage(params.canvas,0,0);
+
+                       params.canvas.width = width;
+                       params.canvas.height = height;
+                       params.canvas.getContext("2d").clearRect(0,0,width,height);
+
+                       params.canvas.getContext("2d").drawImage(copy,
+                               left,top,width,height,
+                               0,0,width,height
+                       );
+
+                       params.useData = false;
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvas();
+       }
+}
+
+
+/*
+ * Pixastic Lib - Desaturation filter - v0.1.1
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.desaturate = {
+
+       process : function(params) {
+               var useAverage = !!(params.options.average && params.options.average != "false");
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var p = w*h;
+                       var pix = p*4, pix1, pix2;
+
+                       if (useAverage) {
+                               while (p--) 
+                                       data[pix-=4] = data[pix1=pix+1] = data[pix2=pix+2] = (data[pix]+data[pix1]+data[pix2])/3
+                       } else {
+                               while (p--)
+                                       data[pix-=4] = data[pix1=pix+1] = data[pix2=pix+2] = (data[pix]*0.3 + data[pix1]*0.59 + data[pix2]*0.11);
+                       }
+                       return true;
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " gray";
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
+       }
+}/*
+ * Pixastic Lib - Edge detection filter - v0.1.1
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.edges = {
+       process : function(params) {
+
+               var mono = !!(params.options.mono && params.options.mono != "false");
+               var invert = !!(params.options.invert && params.options.invert != "false");
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       var c = -1/8;
+                       var kernel = [
+                               [c,     c,      c],
+                               [c,     1,      c],
+                               [c,     c,      c]
+                       ];
+
+                       weight = 1/c;
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var nextY = (y == h) ? y - 1 : y;
+                               var prevY = (y == 1) ? 0 : y-2;
+
+                               var offsetYPrev = prevY*w*4;
+                               var offsetYNext = nextY*w*4;
+
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
+       
+                                       var r = ((dataCopy[offsetPrev-4]
+                                               + dataCopy[offsetPrev]
+                                               + dataCopy[offsetPrev+4]
+                                               + dataCopy[offset-4]
+                                               + dataCopy[offset+4]
+                                               + dataCopy[offsetNext-4]
+                                               + dataCopy[offsetNext]
+                                               + dataCopy[offsetNext+4]) * c
+                                               + dataCopy[offset]
+                                               ) 
+                                               * weight;
+       
+                                       var g = ((dataCopy[offsetPrev-3]
+                                               + dataCopy[offsetPrev+1]
+                                               + dataCopy[offsetPrev+5]
+                                               + dataCopy[offset-3]
+                                               + dataCopy[offset+5]
+                                               + dataCopy[offsetNext-3]
+                                               + dataCopy[offsetNext+1]
+                                               + dataCopy[offsetNext+5]) * c
+                                               + dataCopy[offset+1])
+                                               * weight;
+       
+                                       var b = ((dataCopy[offsetPrev-2]
+                                               + dataCopy[offsetPrev+2]
+                                               + dataCopy[offsetPrev+6]
+                                               + dataCopy[offset-2]
+                                               + dataCopy[offset+6]
+                                               + dataCopy[offsetNext-2]
+                                               + dataCopy[offsetNext+2]
+                                               + dataCopy[offsetNext+6]) * c
+                                               + dataCopy[offset+2])
+                                               * weight;
+
+                                       if (mono) {
+                                               var brightness = (r*0.3 + g*0.59 + b*0.11)||0;
+                                               if (invert) brightness = 255 - brightness;
+                                               if (brightness < 0 ) brightness = 0;
+                                               if (brightness > 255 ) brightness = 255;
+                                               r = g = b = brightness;
+                                       } else {
+                                               if (invert) {
+                                                       r = 255 - r;
+                                                       g = 255 - g;
+                                                       b = 255 - b;
+                                               }
+                                               if (r < 0 ) r = 0;
+                                               if (g < 0 ) g = 0;
+                                               if (b < 0 ) b = 0;
+                                               if (r > 255 ) r = 255;
+                                               if (g > 255 ) g = 255;
+                                               if (b > 255 ) b = 255;
+                                       }
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}/*
+ * Pixastic Lib - Edge detection 2 - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ * 
+ * Contribution by Oliver Hunt (http://nerget.com/, http://nerget.com/canvas/edgeDetection.js). Thanks Oliver!
+ *
+ */
+
+Pixastic.Actions.edges2 = {
+       process : function(params) {
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w * 4;
+                       var pixel = w4 + 4; // Start at (1,1)
+                       var hm1 = h - 1;
+                       var wm1 = w - 1;
+                       for (var y = 1; y < hm1; ++y) {
+                               // Prepare initial cached values for current row
+                               var centerRow = pixel - 4;
+                               var priorRow = centerRow - w4;
+                               var nextRow = centerRow + w4;
+                               
+                               var r1 = - dataCopy[priorRow]   - dataCopy[centerRow]   - dataCopy[nextRow];
+                               var g1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];
+                               var b1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];
+                               
+                               var rp = dataCopy[priorRow += 2];
+                               var gp = dataCopy[++priorRow];
+                               var bp = dataCopy[++priorRow];
+                               
+                               var rc = dataCopy[centerRow += 2];
+                               var gc = dataCopy[++centerRow];
+                               var bc = dataCopy[++centerRow];
+                               
+                               var rn = dataCopy[nextRow += 2];
+                               var gn = dataCopy[++nextRow];
+                               var bn = dataCopy[++nextRow];
+                               
+                               var r2 = - rp - rc - rn;
+                               var g2 = - gp - gc - gn;
+                               var b2 = - bp - bc - bn;
+                               
+                               // Main convolution loop
+                               for (var x = 1; x < wm1; ++x) {
+                                       centerRow = pixel + 4;
+                                       priorRow = centerRow - w4;
+                                       nextRow = centerRow + w4;
+                                       
+                                       var r = 127 + r1 - rp - (rc * -8) - rn;
+                                       var g = 127 + g1 - gp - (gc * -8) - gn;
+                                       var b = 127 + b1 - bp - (bc * -8) - bn;
+                                       
+                                       r1 = r2;
+                                       g1 = g2;
+                                       b1 = b2;
+                                       
+                                       rp = dataCopy[  priorRow];
+                                       gp = dataCopy[++priorRow];
+                                       bp = dataCopy[++priorRow];
+                                       
+                                       rc = dataCopy[  centerRow];
+                                       gc = dataCopy[++centerRow];
+                                       bc = dataCopy[++centerRow];
+                                       
+                                       rn = dataCopy[  nextRow];
+                                       gn = dataCopy[++nextRow];
+                                       bn = dataCopy[++nextRow];
+                                       
+                                       r += (r2 = - rp - rc - rn);
+                                       g += (g2 = - gp - gc - gn);
+                                       b += (b2 = - bp - bc - bn);
+
+                                       if (r > 255) r = 255;
+                                       if (g > 255) g = 255;
+                                       if (b > 255) b = 255;
+                                       if (r < 0) r = 0;
+                                       if (g < 0) g = 0;
+                                       if (b < 0) b = 0;
+
+                                       data[pixel] = r;
+                                       data[++pixel] = g;
+                                       data[++pixel] = b;
+                                       //data[++pixel] = 255; // alpha
+
+                                       pixel+=2;
+                               }
+                               pixel += 8;
+                       }
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}/*
+ * Pixastic Lib - Emboss filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.emboss = {
+       process : function(params) {
+
+               var strength = parseFloat(params.options.strength)||1;
+               var greyLevel = typeof params.options.greyLevel != "undefined" ? parseInt(params.options.greyLevel) : 180;
+               var direction = params.options.direction||"topleft";
+               var blend = !!(params.options.blend && params.options.blend != "false");
+
+               var dirY = 0;
+               var dirX = 0;
+
+               switch (direction) {
+                       case "topleft":                 // top left
+                               dirY = -1;
+                               dirX = -1;
+                               break;
+                       case "top":                     // top
+                               dirY = -1;
+                               dirX = 0;
+                               break;
+                       case "topright":                        // top right
+                               dirY = -1;
+                               dirX = 1;
+                               break;
+                       case "right":                   // right
+                               dirY = 0;
+                               dirX = 1;
+                               break;
+                       case "bottomright":                     // bottom right
+                               dirY = 1;
+                               dirX = 1;
+                               break;
+                       case "bottom":                  // bottom
+                               dirY = 1;
+                               dirX = 0;
+                               break;
+                       case "bottomleft":                      // bottom left
+                               dirY = 1;
+                               dirX = -1;
+                               break;
+                       case "left":                    // left
+                               dirY = 0;
+                               dirX = -1;
+                               break;
+               }
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       var invertAlpha = !!params.options.invertAlpha;
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var otherY = dirY;
+                               if (y + otherY < 1) otherY = 0;
+                               if (y + otherY > h) otherY = 0;
+
+                               var offsetYOther = (y-1+otherY)*w*4;
+
+                               var x = w;
+                               do {
+                                               var offset = offsetY + (x-1)*4;
+
+                                               var otherX = dirX;
+                                               if (x + otherX < 1) otherX = 0;
+                                               if (x + otherX > w) otherX = 0;
+
+                                               var offsetOther = offsetYOther + (x-1+otherX)*4;
+
+                                               var dR = dataCopy[offset] - dataCopy[offsetOther];
+                                               var dG = dataCopy[offset+1] - dataCopy[offsetOther+1];
+                                               var dB = dataCopy[offset+2] - dataCopy[offsetOther+2];
+
+                                               var dif = dR;
+                                               var absDif = dif > 0 ? dif : -dif;
+
+                                               var absG = dG > 0 ? dG : -dG;
+                                               var absB = dB > 0 ? dB : -dB;
+
+                                               if (absG > absDif) {
+                                                       dif = dG;
+                                               }
+                                               if (absB > absDif) {
+                                                       dif = dB;
+                                               }
+
+                                               dif *= strength;
+
+                                               if (blend) {
+                                                       var r = data[offset] + dif;
+                                                       var g = data[offset+1] + dif;
+                                                       var b = data[offset+2] + dif;
+
+                                                       data[offset] = (r > 255) ? 255 : (r < 0 ? 0 : r);
+                                                       data[offset+1] = (g > 255) ? 255 : (g < 0 ? 0 : g);
+                                                       data[offset+2] = (b > 255) ? 255 : (b < 0 ? 0 : b);
+                                               } else {
+                                                       var grey = greyLevel - dif;
+                                                       if (grey < 0) {
+                                                               grey = 0;
+                                                       } else if (grey > 255) {
+                                                               grey = 255;
+                                                       }
+
+                                                       data[offset] = data[offset+1] = data[offset+2] = grey;
+                                               }
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " progid:DXImageTransform.Microsoft.emboss()";
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
+       }
+
+}
+/*
+ * Pixastic Lib - Flip - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.flip = {
+       process : function(params) {
+               var rect = params.options.rect;
+               var copyCanvas = document.createElement("canvas");
+               copyCanvas.width = rect.width;
+               copyCanvas.height = rect.height;
+               copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);
+
+               var ctx = params.canvas.getContext("2d");
+               ctx.clearRect(rect.left, rect.top, rect.width, rect.height);
+
+               if (params.options.axis == "horizontal") {
+                       ctx.scale(-1,1);
+                       ctx.drawImage(copyCanvas, -rect.left-rect.width, rect.top, rect.width, rect.height)
+               } else {
+                       ctx.scale(1,-1);
+                       ctx.drawImage(copyCanvas, rect.left, -rect.top-rect.height, rect.width, rect.height)
+               }
+
+               params.useData = false;
+
+               return true;            
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvas();
+       }
+}
+
+/*
+ * Pixastic Lib - Horizontal flip - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.fliph = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvas()) {
+                       var rect = params.options.rect;
+                       var copyCanvas = document.createElement("canvas");
+                       copyCanvas.width = rect.width;
+                       copyCanvas.height = rect.height;
+                       copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);
+
+                       var ctx = params.canvas.getContext("2d");
+                       ctx.clearRect(rect.left, rect.top, rect.width, rect.height);
+                       ctx.scale(-1,1);
+                       ctx.drawImage(copyCanvas, -rect.left-rect.width, rect.top, rect.width, rect.height)
+                       params.useData = false;
+
+                       return true;            
+
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " fliph";
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());
+       }
+}
+
+/*
+ * Pixastic Lib - Vertical flip - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.flipv = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvas()) {
+                       var rect = params.options.rect;
+                       var copyCanvas = document.createElement("canvas");
+                       copyCanvas.width = rect.width;
+                       copyCanvas.height = rect.height;
+                       copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);
+
+                       var ctx = params.canvas.getContext("2d");
+                       ctx.clearRect(rect.left, rect.top, rect.width, rect.height);
+                       ctx.scale(1,-1);
+                       ctx.drawImage(copyCanvas, rect.left, -rect.top-rect.height, rect.width, rect.height)
+                       params.useData = false;
+
+                       return true;            
+
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " flipv";
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());
+       }
+}
+
+/*
+ * Pixastic Lib - Glow - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+
+Pixastic.Actions.glow = {
+       process : function(params) {
+
+               var amount = (parseFloat(params.options.amount)||0);
+               var blurAmount = parseFloat(params.options.radius)||0;
+
+               amount = Math.min(1,Math.max(0,amount));
+               blurAmount = Math.min(5,Math.max(0,blurAmount));
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var rect = params.options.rect;
+
+                       var blurCanvas = document.createElement("canvas");
+                       blurCanvas.width = params.width;
+                       blurCanvas.height = params.height;
+                       var blurCtx = blurCanvas.getContext("2d");
+                       blurCtx.drawImage(params.canvas,0,0);
+
+                       var scale = 2;
+                       var smallWidth = Math.round(params.width / scale);
+                       var smallHeight = Math.round(params.height / scale);
+
+                       var copy = document.createElement("canvas");
+                       copy.width = smallWidth;
+                       copy.height = smallHeight;
+
+                       var clear = true;
+                       var steps = Math.round(blurAmount * 20);
+
+                       var copyCtx = copy.getContext("2d");
+                       for (var i=0;i<steps;i++) {
+                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));
+                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));
+       
+                               copyCtx.clearRect(0,0,smallWidth,smallHeight);
+       
+                               copyCtx.drawImage(
+                                       blurCanvas,
+                                       0,0,params.width,params.height,
+                                       0,0,scaledWidth,scaledHeight
+                               );
+       
+                               blurCtx.clearRect(0,0,params.width,params.height);
+       
+                               blurCtx.drawImage(
+                                       copy,
+                                       0,0,scaledWidth,scaledHeight,
+                                       0,0,params.width,params.height
+                               );
+                       }
+
+                       var data = Pixastic.prepareData(params);
+                       var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var r = data[offset] + amount * blurData[offset];
+                                       var g = data[offset+1] + amount * blurData[offset+1];
+                                       var b = data[offset+2] + amount * blurData[offset+2];
+       
+                                       if (r > 255) r = 255;
+                                       if (g > 255) g = 255;
+                                       if (b > 255) b = 255;
+                                       if (r < 0) r = 0;
+                                       if (g < 0) g = 0;
+                                       if (b < 0) b = 0;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
+
+
+/*
+ * Pixastic Lib - Histogram - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.histogram = {
+       process : function(params) {
+
+               var average = !!(params.options.average && params.options.average != "false");
+               var paint = !!(params.options.paint && params.options.paint != "false");
+               var color = params.options.color || "rgba(255,255,255,0.5)";
+               var values = [];
+               if (typeof params.options.returnValue != "object") {
+                       params.options.returnValue = {values:[]};
+               }
+               var returnValue = params.options.returnValue;
+               if (typeof returnValue.values != "array") {
+                       returnValue.values = [];
+               }
+               values = returnValue.values;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       params.useData = false;
+
+                       for (var i=0;i<256;i++) {
+                               values[i] = 0;
+                       }
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+                                       var brightness = average ? 
+                                               Math.round((data[offset]+data[offset+1]+data[offset+2])/3)
+                                               : Math.round(data[offset]*0.3 + data[offset+1]*0.59 + data[offset+2]*0.11);
+                                       values[brightness]++;
+
+                               } while (--x);
+                       } while (--y);
+
+                       if (paint) {
+                               var maxValue = 0;
+                               for (var i=0;i<256;i++) {
+                                       if (values[i] > maxValue) {
+                                               maxValue = values[i];
+                                       }
+                               }
+                               var heightScale = params.height / maxValue;
+                               var widthScale = params.width / 256;
+                               var ctx = params.canvas.getContext("2d");
+                               ctx.fillStyle = color;
+                               for (var i=0;i<256;i++) {
+                                       ctx.fillRect(
+                                               i * widthScale, params.height - heightScale * values[i],
+                                               widthScale, values[i] * heightScale
+                                       );
+                               }
+                       }
+
+                       returnValue.values = values;
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+/*
+ * Pixastic Lib - HSL Adjust  - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.hsl = {
+       process : function(params) {
+
+               var hue = parseInt(params.options.hue,10)||0;
+               var saturation = (parseInt(params.options.saturation,10)||0) / 100;
+               var lightness = (parseInt(params.options.lightness,10)||0) / 100;
+
+
+               // this seems to give the same result as Photoshop
+               if (saturation < 0) {
+                       var satMul = 1+saturation;
+               } else {
+                       var satMul = 1+saturation*2;
+               }
+
+               hue = (hue%360) / 360;
+               var hue6 = hue * 6;
+
+               var rgbDiv = 1 / 255;
+
+               var light255 = lightness * 255;
+               var lightp1 = 1 + lightness;
+               var lightm1 = 1 - lightness;
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var r = data[offset];
+                                       var g = data[offset+1];
+                                       var b = data[offset+2];
+
+                                       if (hue != 0 || saturation != 0) {
+                                               // ok, here comes rgb to hsl + adjust + hsl to rgb, all in one jumbled mess. 
+                                               // It's not so pretty, but it's been optimized to get somewhat decent performance.
+                                               // The transforms were originally adapted from the ones found in Graphics Gems, but have been heavily modified.
+                                               var vs = r;
+                                               if (g > vs) vs = g;
+                                               if (b > vs) vs = b;
+                                               var ms = r;
+                                               if (g < ms) ms = g;
+                                               if (b < ms) ms = b;
+                                               var vm = (vs-ms);
+                                               var l = (ms+vs)/255 * 0.5;
+                                               if (l > 0) {
+                                                       if (vm > 0) {
+                                                               if (l <= 0.5) {
+                                                                       var s = vm / (vs+ms) * satMul;
+                                                                       if (s > 1) s = 1;
+                                                                       var v = (l * (1+s));
+                                                               } else {
+                                                                       var s = vm / (510-vs-ms) * satMul;
+                                                                       if (s > 1) s = 1;
+                                                                       var v = (l+s - l*s);
+                                                               }
+                                                               if (r == vs) {
+                                                                       if (g == ms)
+                                                                               var h = 5 + ((vs-b)/vm) + hue6;
+                                                                       else
+                                                                               var h = 1 - ((vs-g)/vm) + hue6;
+                                                               } else if (g == vs) {
+                                                                       if (b == ms)
+                                                                               var h = 1 + ((vs-r)/vm) + hue6;
+                                                                       else
+                                                                               var h = 3 - ((vs-b)/vm) + hue6;
+                                                               } else {
+                                                                       if (r == ms)
+                                                                               var h = 3 + ((vs-g)/vm) + hue6;
+                                                                       else
+                                                                               var h = 5 - ((vs-r)/vm) + hue6;
+                                                               }
+                                                               if (h < 0) h+=6;
+                                                               if (h >= 6) h-=6;
+                                                               var m = (l+l-v);
+                                                               var sextant = h>>0;
+                                                               switch (sextant) {
+                                                                       case 0: r = v*255; g = (m+((v-m)*(h-sextant)))*255; b = m*255; break;
+                                                                       case 1: r = (v-((v-m)*(h-sextant)))*255; g = v*255; b = m*255; break;
+                                                                       case 2: r = m*255; g = v*255; b = (m+((v-m)*(h-sextant)))*255; break;
+                                                                       case 3: r = m*255; g = (v-((v-m)*(h-sextant)))*255; b = v*255; break;
+                                                                       case 4: r = (m+((v-m)*(h-sextant)))*255; g = m*255; b = v*255; break;
+                                                                       case 5: r = v*255; g = m*255; b = (v-((v-m)*(h-sextant)))*255; break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+
+                                       if (lightness < 0) {
+                                               r *= lightp1;
+                                               g *= lightp1;
+                                               b *= lightp1;
+                                       } else if (lightness > 0) {
+                                               r = r * lightm1 + light255;
+                                               g = g * lightm1 + light255;
+                                               b = b * lightm1 + light255;
+                                       }
+
+                                       if (r < 0) r = 0;
+                                       if (g < 0) g = 0;
+                                       if (b < 0) b = 0;
+                                       if (r > 255) r = 255;
+                                       if (g > 255) g = 255;
+                                       if (b > 255) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+
+}
+/*
+ * Pixastic Lib - Invert filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.invert = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+
+                       var invertAlpha = !!params.options.invertAlpha;
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+                                       data[offset] = 255 - data[offset];
+                                       data[offset+1] = 255 - data[offset+1];
+                                       data[offset+2] = 255 - data[offset+2];
+                                       if (invertAlpha) data[offset+3] = 255 - data[offset+3];
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " invert";
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
+       }
+}
+/*
+ * Pixastic Lib - Laplace filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.laplace = {
+       process : function(params) {
+
+               var strength = 1.0;
+               var invert = !!(params.options.invert && params.options.invert != "false");
+               var contrast = parseFloat(params.options.edgeStrength)||0;
+
+               var greyLevel = parseInt(params.options.greyLevel)||0;
+
+               contrast = -contrast;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       var kernel = [
+                               [-1,    -1,     -1],
+                               [-1,    8,      -1],
+                               [-1,    -1,     -1]
+                       ];
+
+                       var weight = 1/8;
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var nextY = (y == h) ? y - 1 : y;
+                               var prevY = (y == 1) ? 0 : y-2;
+
+                               var offsetYPrev = prevY*w*4;
+                               var offsetYNext = nextY*w*4;
+
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
+       
+                                       var r = ((-dataCopy[offsetPrev-4]
+                                               - dataCopy[offsetPrev]
+                                               - dataCopy[offsetPrev+4]
+                                               - dataCopy[offset-4]
+                                               - dataCopy[offset+4]
+                                               - dataCopy[offsetNext-4]
+                                               - dataCopy[offsetNext]
+                                               - dataCopy[offsetNext+4])
+                                               + dataCopy[offset] * 8) 
+                                               * weight;
+       
+                                       var g = ((-dataCopy[offsetPrev-3]
+                                               - dataCopy[offsetPrev+1]
+                                               - dataCopy[offsetPrev+5]
+                                               - dataCopy[offset-3]
+                                               - dataCopy[offset+5]
+                                               - dataCopy[offsetNext-3]
+                                               - dataCopy[offsetNext+1]
+                                               - dataCopy[offsetNext+5])
+                                               + dataCopy[offset+1] * 8)
+                                               * weight;
+       
+                                       var b = ((-dataCopy[offsetPrev-2]
+                                               - dataCopy[offsetPrev+2]
+                                               - dataCopy[offsetPrev+6]
+                                               - dataCopy[offset-2]
+                                               - dataCopy[offset+6]
+                                               - dataCopy[offsetNext-2]
+                                               - dataCopy[offsetNext+2]
+                                               - dataCopy[offsetNext+6])
+                                               + dataCopy[offset+2] * 8)
+                                               * weight;
+
+                                       var brightness = ((r + g + b)/3) + greyLevel;
+
+                                       if (contrast != 0) {
+                                               if (brightness > 127) {
+                                                       brightness += ((brightness + 1) - 128) * contrast;
+                                               } else if (brightness < 127) {
+                                                       brightness -= (brightness + 1) * contrast;
+                                               }
+                                       }
+                                       if (invert) {
+                                               brightness = 255 - brightness;
+                                       }
+                                       if (brightness < 0 ) brightness = 0;
+                                       if (brightness > 255 ) brightness = 255;
+
+                                       data[offset] = data[offset+1] = data[offset+2] = brightness;
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
+/*
+ * Pixastic Lib - Lighten filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.lighten = {
+
+       process : function(params) {
+               var amount = parseFloat(params.options.amount) || 0;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+
+                                       var r = data[offset];
+                                       var g = data[offset+1];
+                                       var b = data[offset+2];
+
+                                       r += r*amount;
+                                       g += g*amount;
+                                       b += b*amount;
+
+                                       if (r < 0 ) r = 0;
+                                       if (g < 0 ) g = 0;
+                                       if (b < 0 ) b = 0;
+                                       if (r > 255 ) r = 255;
+                                       if (g > 255 ) g = 255;
+                                       if (b > 255 ) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+
+               } else if (Pixastic.Client.isIE()) {
+                       var img = params.image;
+                       if (amount < 0) {
+                               img.style.filter += " light()";
+                               img.filters[img.filters.length-1].addAmbient(
+                                       255,255,255,
+                                       100 * -amount
+                               );
+                       } else if (amount > 0) {
+                               img.style.filter += " light()";
+                               img.filters[img.filters.length-1].addAmbient(
+                                       255,255,255,
+                                       100
+                               );
+                               img.filters[img.filters.length-1].addAmbient(
+                                       255,255,255,
+                                       100 * amount
+                               );
+                       }
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
+       }
+}
+/*
+ * Pixastic Lib - Mosaic filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.mosaic = {
+
+       process : function(params) {
+               var blockSize = Math.max(1,parseInt(params.options.blockSize,10));
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+
+                       var ctx = params.canvas.getContext("2d");
+
+                       var pixel = document.createElement("canvas");
+                       pixel.width = pixel.height = 1;
+                       var pixelCtx = pixel.getContext("2d");
+
+                       var copy = document.createElement("canvas");
+                       copy.width = w;
+                       copy.height = h;
+                       var copyCtx = copy.getContext("2d");
+                       copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);
+
+                       for (var y=0;y<h;y+=blockSize) {
+                               for (var x=0;x<w;x+=blockSize) {
+                                       var blockSizeX = blockSize;
+                                       var blockSizeY = blockSize;
+               
+                                       if (blockSizeX + x > w)
+                                               blockSizeX = w - x;
+                                       if (blockSizeY + y > h)
+                                               blockSizeY = h - y;
+
+                                       pixelCtx.drawImage(copy, x, y, blockSizeX, blockSizeY, 0, 0, 1, 1);
+                                       var data = pixelCtx.getImageData(0,0,1,1).data;
+                                       ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";
+                                       ctx.fillRect(rect.left + x, rect.top + y, blockSize, blockSize);
+                               }
+                       }
+                       params.useData = false;
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData());
+       }
+}/*
+ * Pixastic Lib - Noise filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.noise = {
+
+       process : function(params) {
+               var amount = 0;
+               var strength = 0;
+               var mono = false;
+
+               if (typeof params.options.amount != "undefined")
+                       amount = parseFloat(params.options.amount)||0;
+               if (typeof params.options.strength != "undefined")
+                       strength = parseFloat(params.options.strength)||0;
+               if (typeof params.options.mono != "undefined")
+                       mono = !!(params.options.mono && params.options.mono != "false");
+
+               amount = Math.max(0,Math.min(1,amount));
+               strength = Math.max(0,Math.min(1,strength));
+
+               var noise = 128 * strength;
+               var noise2 = noise / 2;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       var random = Math.random;
+
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+                                       if (random() < amount) {
+                                               if (mono) {
+                                                       var pixelNoise = - noise2 + random() * noise;
+                                                       var r = data[offset] + pixelNoise;
+                                                       var g = data[offset+1] + pixelNoise;
+                                                       var b = data[offset+2] + pixelNoise;
+                                               } else {
+                                                       var r = data[offset] - noise2 + (random() * noise);
+                                                       var g = data[offset+1] - noise2 + (random() * noise);
+                                                       var b = data[offset+2] - noise2 + (random() * noise);
+                                               }
+
+                                               if (r < 0 ) r = 0;
+                                               if (g < 0 ) g = 0;
+                                               if (b < 0 ) b = 0;
+                                               if (r > 255 ) r = 255;
+                                               if (g > 255 ) g = 255;
+                                               if (b > 255 ) b = 255;
+
+                                               data[offset] = r;
+                                               data[offset+1] = g;
+                                               data[offset+2] = b;
+                                       }
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
+/*
+ * Pixastic Lib - Posterize effect - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.posterize = {
+
+       process : function(params) {
+
+               
+               var numLevels = 256;
+               if (typeof params.options.levels != "undefined")
+                       numLevels = parseInt(params.options.levels,10)||1;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+
+                       numLevels = Math.max(2,Math.min(256,numLevels));
+       
+                       var numAreas = 256 / numLevels;
+                       var numValues = 256 / (numLevels-1);
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+
+                                       var r = numValues * ((data[offset] / numAreas)>>0);
+                                       var g = numValues * ((data[offset+1] / numAreas)>>0);
+                                       var b = numValues * ((data[offset+2] / numAreas)>>0);
+
+                                       if (r > 255) r = 255;
+                                       if (g > 255) g = 255;
+                                       if (b > 255) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
+
+/*
+ * Pixastic Lib - Pointillize filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.pointillize = {
+
+       process : function(params) {
+               var radius = Math.max(1,parseInt(params.options.radius,10));
+               var density = Math.min(5,Math.max(0,parseFloat(params.options.density)||0));
+               var noise = Math.max(0,parseFloat(params.options.noise)||0);
+               var transparent = !!(params.options.transparent && params.options.transparent != "false");
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+
+                       var ctx = params.canvas.getContext("2d");
+                       var canvasWidth = params.canvas.width;
+                       var canvasHeight = params.canvas.height;
+
+                       var pixel = document.createElement("canvas");
+                       pixel.width = pixel.height = 1;
+                       var pixelCtx = pixel.getContext("2d");
+
+                       var copy = document.createElement("canvas");
+                       copy.width = w;
+                       copy.height = h;
+                       var copyCtx = copy.getContext("2d");
+                       copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);
+
+                       var diameter = radius * 2;
+
+                       if (transparent)
+                               ctx.clearRect(rect.left, rect.top, rect.width, rect.height);
+
+                       var noiseRadius = radius * noise;
+
+                       var dist = 1 / density;
+
+                       for (var y=0;y<h+radius;y+=diameter*dist) {
+                               for (var x=0;x<w+radius;x+=diameter*dist) {
+                                       rndX = noise ? (x+((Math.random()*2-1) * noiseRadius))>>0 : x;
+                                       rndY = noise ? (y+((Math.random()*2-1) * noiseRadius))>>0 : y;
+
+                                       var pixX = rndX - radius;
+                                       var pixY = rndY - radius;
+                                       if (pixX < 0) pixX = 0;
+                                       if (pixY < 0) pixY = 0;
+
+                                       var cx = rndX + rect.left;
+                                       var cy = rndY + rect.top;
+                                       if (cx < 0) cx = 0;
+                                       if (cx > canvasWidth) cx = canvasWidth;
+                                       if (cy < 0) cy = 0;
+                                       if (cy > canvasHeight) cy = canvasHeight;
+
+                                       var diameterX = diameter;
+                                       var diameterY = diameter;
+
+                                       if (diameterX + pixX > w)
+                                               diameterX = w - pixX;
+                                       if (diameterY + pixY > h)
+                                               diameterY = h - pixY;
+                                       if (diameterX < 1) diameterX = 1;
+                                       if (diameterY < 1) diameterY = 1;
+
+                                       pixelCtx.drawImage(copy, pixX, pixY, diameterX, diameterY, 0, 0, 1, 1);
+                                       var data = pixelCtx.getImageData(0,0,1,1).data;
+
+                                       ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";
+                                       ctx.beginPath();
+                                       ctx.arc(cx, cy, radius, 0, Math.PI*2, true);
+                                       ctx.closePath();
+                                       ctx.fill();
+                               }
+                       }
+
+                       params.useData = false;
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData());
+       }
+}/*
+ * Pixastic Lib - Resize - v0.1.0
+ * Copyright (c) 2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.resize = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvas()) {
+                       var width = parseInt(params.options.width,10);
+                       var height = parseInt(params.options.height,10);
+                       var canvas = params.canvas;
+
+                       if (width < 1) width = 1;
+                       if (width < 2) width = 2;
+
+                       var copy = document.createElement("canvas");
+                       copy.width = width;
+                       copy.height = height;
+
+                       copy.getContext("2d").drawImage(canvas,0,0,width,height);
+                       canvas.width = width;
+                       canvas.height = height;
+
+                       canvas.getContext("2d").drawImage(copy,0,0);
+
+                       params.useData = false;
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvas();
+       }
+}
+
+
+/*
+ * Pixastic Lib - Remove noise - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.removenoise = {
+       process : function(params) {
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var nextY = (y == h) ? y - 1 : y;
+                               var prevY = (y == 1) ? 0 : y-2;
+
+                               var offsetYPrev = prevY*w*4;
+                               var offsetYNext = nextY*w*4;
+
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
+
+                                       var minR, maxR, minG, maxG, minB, maxB;
+
+                                       minR = maxR = data[offsetPrev];
+                                       var r1 = data[offset-4], r2 = data[offset+4], r3 = data[offsetNext];
+                                       if (r1 < minR) minR = r1;
+                                       if (r2 < minR) minR = r2;
+                                       if (r3 < minR) minR = r3;
+                                       if (r1 > maxR) maxR = r1;
+                                       if (r2 > maxR) maxR = r2;
+                                       if (r3 > maxR) maxR = r3;
+
+                                       minG = maxG = data[offsetPrev+1];
+                                       var g1 = data[offset-3], g2 = data[offset+5], g3 = data[offsetNext+1];
+                                       if (g1 < minG) minG = g1;
+                                       if (g2 < minG) minG = g2;
+                                       if (g3 < minG) minG = g3;
+                                       if (g1 > maxG) maxG = g1;
+                                       if (g2 > maxG) maxG = g2;
+                                       if (g3 > maxG) maxG = g3;
+
+                                       minB = maxB = data[offsetPrev+2];
+                                       var b1 = data[offset-2], b2 = data[offset+6], b3 = data[offsetNext+2];
+                                       if (b1 < minB) minB = b1;
+                                       if (b2 < minB) minB = b2;
+                                       if (b3 < minB) minB = b3;
+                                       if (b1 > maxB) maxB = b1;
+                                       if (b2 > maxB) maxB = b2;
+                                       if (b3 > maxB) maxB = b3;
+
+                                       if (data[offset] > maxR) {
+                                               data[offset] = maxR;
+                                       } else if (data[offset] < minR) {
+                                               data[offset] = minR;
+                                       }
+                                       if (data[offset+1] > maxG) {
+                                               data[offset+1] = maxG;
+                                       } else if (data[offset+1] < minG) {
+                                               data[offset+1] = minG;
+                                       }
+                                       if (data[offset+2] > maxB) {
+                                               data[offset+2] = maxB;
+                                       } else if (data[offset+2] < minB) {
+                                               data[offset+2] = minB;
+                                       }
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}/*
+ * Pixastic Lib - Rotate - v0.1.0
+ * Copyright (c) 2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.rotate = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvas()) {
+                       var canvas = params.canvas;
+
+                       var width = params.width;
+                       var height = params.height;
+
+                       var copy = document.createElement("canvas");
+                       copy.width = width;
+                       copy.height = height;
+                       copy.getContext("2d").drawImage(canvas,0,0,width,height);
+
+                       var angle = -parseFloat(params.options.angle) * Math.PI / 180;
+
+                       var dimAngle = angle;
+                       if (dimAngle > Math.PI*0.5)
+                               dimAngle = Math.PI - dimAngle;
+                       if (dimAngle < -Math.PI*0.5)
+                               dimAngle = -Math.PI - dimAngle;
+
+                       var diag = Math.sqrt(width*width + height*height);
+
+                       var diagAngle1 = Math.abs(dimAngle) - Math.abs(Math.atan2(height, width));
+                       var diagAngle2 = Math.abs(dimAngle) + Math.abs(Math.atan2(height, width));
+
+                       var newWidth = Math.abs(Math.cos(diagAngle1) * diag);
+                       var newHeight = Math.abs(Math.sin(diagAngle2) * diag);
+
+                       canvas.width = newWidth;
+                       canvas.height = newHeight;
+
+                       var ctx = canvas.getContext("2d");
+                       ctx.translate(newWidth/2, newHeight/2);
+                       ctx.rotate(angle);
+                       ctx.drawImage(copy,-width/2,-height/2);
+
+                       params.useData = false;
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvas();
+       }
+}
+
+
+/*
+ * Pixastic Lib - Sepia filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.sepia = {
+
+       process : function(params) {
+               var mode = (parseInt(params.options.mode,10)||0);
+               if (mode < 0) mode = 0;
+               if (mode > 1) mode = 1;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+
+                                       if (mode) {
+                                               // a bit faster, but not as good
+                                               var d = data[offset] * 0.299 + data[offset+1] * 0.587 + data[offset+2] * 0.114;
+                                               var r = (d + 39);
+                                               var g = (d + 14);
+                                               var b = (d - 36);
+                                       } else {
+                                               // Microsoft
+                                               var or = data[offset];
+                                               var og = data[offset+1];
+                                               var ob = data[offset+2];
+       
+                                               var r = (or * 0.393 + og * 0.769 + ob * 0.189);
+                                               var g = (or * 0.349 + og * 0.686 + ob * 0.168);
+                                               var b = (or * 0.272 + og * 0.534 + ob * 0.131);
+                                       }
+
+                                       if (r < 0) r = 0; if (r > 255) r = 255;
+                                       if (g < 0) g = 0; if (g > 255) g = 255;
+                                       if (b < 0) b = 0; if (b > 255) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}/*
+ * Pixastic Lib - Sharpen filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.sharpen = {
+       process : function(params) {
+
+               var strength = 0;
+               if (typeof params.options.amount != "undefined")
+                       strength = parseFloat(params.options.amount)||0;
+
+               if (strength < 0) strength = 0;
+               if (strength > 1) strength = 1;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       var mul = 15;
+                       var mulOther = 1 + 3*strength;
+
+                       var kernel = [
+                               [0,     -mulOther,      0],
+                               [-mulOther,     mul,    -mulOther],
+                               [0,     -mulOther,      0]
+                       ];
+
+                       var weight = 0;
+                       for (var i=0;i<3;i++) {
+                               for (var j=0;j<3;j++) {
+                                       weight += kernel[i][j];
+                               }
+                       }
+
+                       weight = 1 / weight;
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       mul *= weight;
+                       mulOther *= weight;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var nextY = (y == h) ? y - 1 : y;
+                               var prevY = (y == 1) ? 0 : y-2;
+
+                               var offsetYPrev = prevY*w4;
+                               var offsetYNext = nextY*w4;
+
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
+
+                                       var r = ((
+                                               - dataCopy[offsetPrev]
+                                               - dataCopy[offset-4]
+                                               - dataCopy[offset+4]
+                                               - dataCopy[offsetNext])         * mulOther
+                                               + dataCopy[offset]      * mul
+                                               );
+
+                                       var g = ((
+                                               - dataCopy[offsetPrev+1]
+                                               - dataCopy[offset-3]
+                                               - dataCopy[offset+5]
+                                               - dataCopy[offsetNext+1])       * mulOther
+                                               + dataCopy[offset+1]    * mul
+                                               );
+
+                                       var b = ((
+                                               - dataCopy[offsetPrev+2]
+                                               - dataCopy[offset-2]
+                                               - dataCopy[offset+6]
+                                               - dataCopy[offsetNext+2])       * mulOther
+                                               + dataCopy[offset+2]    * mul
+                                               );
+
+
+                                       if (r < 0 ) r = 0;
+                                       if (g < 0 ) g = 0;
+                                       if (b < 0 ) b = 0;
+                                       if (r > 255 ) r = 255;
+                                       if (g > 255 ) g = 255;
+                                       if (b > 255 ) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+/*
+ * Pixastic Lib - Solarize filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.solarize = {
+
+       process : function(params) {
+               var useAverage = !!(params.options.average && params.options.average != "false");
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+
+                                       var r = data[offset];
+                                       var g = data[offset+1];
+                                       var b = data[offset+2];
+
+                                       if (r > 127) r = 255 - r;
+                                       if (g > 127) g = 255 - g;
+                                       if (b > 127) b = 255 - b;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData());
+       }
+}/*
+ * Pixastic Lib - USM - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+
+Pixastic.Actions.unsharpmask = {
+       process : function(params) {
+
+               var amount = (parseFloat(params.options.amount)||0);
+               var blurAmount = parseFloat(params.options.radius)||0;
+               var threshold = parseFloat(params.options.threshold)||0;
+
+               amount = Math.min(500,Math.max(0,amount)) / 2;
+               blurAmount = Math.min(5,Math.max(0,blurAmount)) / 10;
+               threshold = Math.min(255,Math.max(0,threshold));
+
+               threshold--;
+               var thresholdNeg = -threshold;
+
+               amount *= 0.016;
+               amount++;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var rect = params.options.rect;
+
+                       var blurCanvas = document.createElement("canvas");
+                       blurCanvas.width = params.width;
+                       blurCanvas.height = params.height;
+                       var blurCtx = blurCanvas.getContext("2d");
+                       blurCtx.drawImage(params.canvas,0,0);
+
+                       var scale = 2;
+                       var smallWidth = Math.round(params.width / scale);
+                       var smallHeight = Math.round(params.height / scale);
+
+                       var copy = document.createElement("canvas");
+                       copy.width = smallWidth;
+                       copy.height = smallHeight;
+
+                       var steps = Math.round(blurAmount * 20);
+
+                       var copyCtx = copy.getContext("2d");
+                       for (var i=0;i<steps;i++) {
+                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));
+                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));
+
+                               copyCtx.clearRect(0,0,smallWidth,smallHeight);
+
+                               copyCtx.drawImage(
+                                       blurCanvas,
+                                       0,0,params.width,params.height,
+                                       0,0,scaledWidth,scaledHeight
+                               );
+       
+                               blurCtx.clearRect(0,0,params.width,params.height);
+       
+                               blurCtx.drawImage(
+                                       copy,
+                                       0,0,scaledWidth,scaledHeight,
+                                       0,0,params.width,params.height
+                               );
+                       }
+
+                       var data = Pixastic.prepareData(params);
+                       var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var difR = data[offset] - blurData[offset];
+                                       if (difR > threshold || difR < thresholdNeg) {
+                                               var blurR = blurData[offset];
+                                               blurR = amount * difR + blurR;
+                                               data[offset] = blurR > 255 ? 255 : (blurR < 0 ? 0 : blurR);
+                                       }
+
+                                       var difG = data[offset+1] - blurData[offset+1];
+                                       if (difG > threshold || difG < thresholdNeg) {
+                                               var blurG = blurData[offset+1];
+                                               blurG = amount * difG + blurG;
+                                               data[offset+1] = blurG > 255 ? 255 : (blurG < 0 ? 0 : blurG);
+                                       }
+
+                                       var difB = data[offset+2] - blurData[offset+2];
+                                       if (difB > threshold || difB < thresholdNeg) {
+                                               var blurB = blurData[offset+2];
+                                               blurB = amount * difB + blurB;
+                                               data[offset+2] = blurB > 255 ? 255 : (blurB < 0 ? 0 : blurB);
+                                       }
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
+
+
+
index a487ba2..bda133c 100644 (file)
-/* http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/ */\r
-\r
-html, body, div, span, applet, object, iframe,\r
-h1, h2, h3, h4, h5, h6, p, blockquote, pre,\r
-a, abbr, acronym, address, big, cite, code,\r
-del, dfn, em, font, img, ins, kbd, q, s, samp,\r
-small, strike, strong, sub, sup, tt, var,\r
-dl, dt, dd, ol, ul, li,\r
-fieldset, form, label, legend,\r
-table, caption, tbody, tfoot, thead, tr, th, td {\r
-       margin: 0;\r
-       padding: 0;\r
-       border: 0;\r
-       outline: 0;\r
-       font-weight: inherit;\r
-       font-style: inherit;\r
-       font-size: 100%;\r
-       font-family: inherit;\r
-       vertical-align: baseline;\r
-}\r
-/* remember to define focus styles! */\r
-:focus {\r
-       outline: 0;\r
-}\r
-body {\r
-       line-height: 1;\r
-       color: black;\r
-       background: white;\r
-}\r
-ol, ul {\r
-       list-style: none;\r
-}\r
-/* tables still need 'cellspacing="0"' in the markup */\r
-table {\r
-       border-collapse: separate;\r
-       border-spacing: 0;\r
-}\r
-caption, th, td {\r
-       text-align: left;\r
-       font-weight: normal;\r
-}\r
-blockquote:before, blockquote:after,\r
-q:before, q:after {\r
-       content: "";\r
-}\r
-blockquote, q {\r
-       quotes: "" "";\r
-}\r
-/* end reset */\r
-\r
-/* -----------------------\r
- *   Base\r
- * -----------------------\r
- */\r
-\r
-/* main container element for editor app */\r
-#pixastic-editor {\r
-       margin : 0;\r
-       position : absolute;\r
-       left : 0;\r
-       top : 0;\r
-       padding: 0px;\r
-       width: 100%;\r
-       height: 100%;\r
-       font-family : Helvetica,Arial,sans-serif;\r
-       overflow : hidden;\r
-       z-index : 10000000;\r
-} \r
-\r
-\r
-/* -----------------------\r
- *   Loading screen\r
- * -----------------------\r
- */\r
-\r
-/* container for loading screen */\r
-#loading-screen {\r
-       margin : 0;\r
-       position : absolute;\r
-       left : 0;\r
-       top : 0;\r
-       padding: 0px;\r
-       width: 100%;\r
-       height: 100%;\r
-       font-family : Helvetica,Arial,sans-serif;\r
-       overflow : hidden;\r
-       z-index : 10000000;\r
-       background-color : #111;\r
-       opacity : 0.9;\r
-       display : table;\r
-       text-align : center;\r
-} \r
-\r
-/* container for spinner in loading screen */\r
-#loading-screen-cell {\r
-       display : table-cell;\r
-       vertical-align : middle;\r
-       text-align : center;\r
-}\r
-\r
-\r
-/* -----------------------\r
- *   Misc\r
- * -----------------------\r
- */\r
-\r
-\r
-// UI error dialog\r
-.ui-dialog .error-dialog {\r
-       background-color : #544;\r
-}\r
-\r
-/* loading spinner */\r
-.spinner {\r
-       width : 31px;\r
-       height : 31px;\r
-       display : inline-block;\r
-       background: url(spinner.gif);\r
-       overflow : hidden;\r
-}\r
-\r
-canvas.display-canvas,\r
-canvas.undo-canvas {\r
-       /*\r
-       background : url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC1JREFUeNpiPHPmDAM2YGxsjFWciYFEMKqBGMD4//9/rBJnz54dDSX6aQAIMABCtQiAsDRF+wAAAABJRU5ErkJggg==');\r
-       */\r
-       background : url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC5JREFUeNpiPHPmTAMDHmBsbIxPmoGJgUIwasBgMICFUDyfPXt2NBCHvwEAAQYAICIGn294LYEAAAAASUVORK5CYII=');\r
-\r
-}\r
-\r
-.far-far-away {\r
-       position : absolute;\r
-       left : -9999px;\r
-       top : -9999px;\r
-}\r
-\r
-#powered-by-pixastic {\r
-       position : absolute;\r
-       bottom : 0px;\r
-       margin-bottom : 23px;\r
-       margin-left : 42px;\r
-}\r
-#powered-by-pixastic a {\r
-       font-size : 12px;\r
-       font-family : Helvetica,Arial,sans-serif;\r
-       letter-spacing : 0.1em;\r
-       color : rgb(100,100,100);\r
-       color : rgba(255,255,255,0.2);\r
-       text-decoration : none;\r
-}\r
-\r
-#powered-by-pixastic a:hover {\r
-       color : rgb(200,200,200);\r
-       color : rgba(255,255,255,0.7);\r
-       text-decoration : underline;\r
-}\r
-\r
-\r
-/* -----------------------\r
- *   Skeleton structure\r
- * -----------------------\r
- */\r
-\r
-/* editor background underlay */\r
-#background {\r
-       background-color : #111;\r
-       opacity : 0.9;\r
-       width : 100%;\r
-       height : 100%;\r
-       position : absolute;\r
-       z-index : -1;\r
-}\r
-\r
-#image-area {\r
-       position : relative;\r
-       background-color : #222;\r
-       border : 1px solid #444;\r
-       width : 100%;\r
-       height : 100%;\r
-       -moz-box-sizing:border-box;\r
-       overflow : auto;\r
-       text-align : center;\r
-}\r
-\r
-#image-area-sub {\r
-}\r
-\r
-#image-container {\r
-}\r
-\r
-#image-overlay-container {\r
-       -moz-box-sizing:border-box;\r
-       width:100%;\r
-       height:100%;\r
-       position:absolute;\r
-       top:0;\r
-       left:0;\r
-}\r
-\r
-#image-overlay {\r
-}\r
-\r
-\r
-/* structure elements */\r
-#edit-ctr-1 {\r
-       position : absolute;\r
-       top : 0;\r
-       left : 0;\r
-       width : 100%;\r
-       height : 100%;\r
-}\r
-\r
-#edit-ctr-2 {\r
-       -moz-box-sizing : border-box;\r
-       box-sizing : border-box;\r
-       padding-left:40px;\r
-       padding-right:420px;\r
-       padding-top:70px;\r
-       padding-bottom : 40px;\r
-       height : 100%;\r
-       width : 100%;\r
-}\r
-\r
-\r
-/* main menu bar */\r
-#main-bar {\r
-       position : absolute;\r
-       width : 100%;\r
-       text-align : right;\r
-       margin-top : 20px;\r
-       margin-right : 30px;\r
-}\r
-\r
-/* area on the right with accordion widgets and undo bar */\r
-#controls-bar {\r
-       margin-right : -385px;\r
-       width : 372px;\r
-       float : right;\r
-       height : 100%;\r
-}\r
-\r
-/* accordion area */\r
-#action-bar {\r
-       padding : 10px;\r
-       width : 290px;\r
-       background-color : #222;\r
-       border : 1px solid #444;\r
-       -moz-box-sizing : border-box;\r
-       box-sizing : border-box;\r
-       height : 100%;\r
-       overflow-x : hidden;\r
-       overflow-y : auto;\r
-       float: right; \r
-       position : relative;\r
-}\r
-\r
-#action-bar-overlay {\r
-       position : absolute;\r
-       z-index : 1000000;\r
-       width : 100%;\r
-       height : 100%;\r
-       left : 0;\r
-       top : 0;\r
-       background-color : #444;\r
-       opacity : 0.2;\r
-       display : none;\r
-}\r
-\r
-\r
-/* vertical bar with undo image states */\r
-#undo-bar {\r
-       -moz-box-sizing : border-box;\r
-       box-sizing : border-box;\r
-       background-color : #222;\r
-       border : 1px solid #444;\r
-       width: 70px; \r
-       height: 100%;\r
-       overflow: hidden;\r
-       padding-top : 3px;\r
-}\r
-\r
-\r
-\r
-/* -----------------------\r
- *   Main menu styles\r
- * -----------------------\r
- */\r
-\r
-.main-tab {\r
-       color : #999;\r
-       display : inline-block;\r
-       width : 150px;\r
-       text-transform : lowercase;\r
-       font-size : 22px;\r
-       cursor : pointer;\r
-       text-align : center;\r
-       text-decoration : none;\r
-       padding-top : 4px;\r
-       padding-bottom : 5px;\r
-       outline : 0;\r
-}\r
-\r
-.main-tab.hover {\r
-       color : white !important;\r
-}\r
-\r
-.main-tab.active {\r
-       color : white;\r
-}\r
-\r
-\r
-\r
-/* -----------------------\r
- *   Undo list\r
- * -----------------------\r
- */\r
-\r
-\r
-.undo-canvas-small {\r
-       width : 60px;\r
-       height : 40px;\r
-       cursor : pointer;\r
-}\r
-\r
-.undo-link {\r
-       width : 60px;\r
-       height : 40px;\r
-       display : block;\r
-       margin : 4px;\r
-       cursor : pointer;\r
-       opacity : 0.8;\r
-}\r
-\r
-.undo-link.hover {\r
-       opacity : 1;\r
-}\r
-\r
-\r
-\r
-/* -----------------------\r
- *   Action UI controls\r
- * -----------------------\r
- */\r
-\r
-\r
-.ui-slider-label, \r
-.ui-checkbox-label, \r
-.ui-textinput-label, \r
-.ui-select-label {\r
-       width : 70px;\r
-       text-align : right;\r
-       margin-right : 5px;\r
-       display : inline-block;\r
-}\r
-\r
-.ui-textinput-label-right {\r
-       margin-left : 5px;\r
-}\r
-\r
-.ui-textinput {\r
-}\r
-\r
-.ui-numericinput {\r
-       width : 35px;\r
-}\r
-\r
-.ui-slider {\r
-       width : 125px;\r
-       display : inline-block;\r
-       margin-left : 3px;\r
-       background-color : #222;\r
-}\r
-\r
-.ui-slider-value {\r
-       font-size : 11px;\r
-       width : 25px;\r
-       display : inline-block;\r
-       margin-left : 10px;\r
-}\r
-\r
-.ui-action-output {\r
-       margin-bottom : 10px;\r
-}\r
-\r
-.ui-accordion .ui-accordion-content-active {\r
-       font-size : 11px;\r
-       overflow : hidden;\r
-}\r
-\r
-.ui-slider-horizontal {\r
-}\r
-\r
-.ui-slider-container, \r
-.ui-checkbox-container, \r
-.ui-textinput-container, \r
-.ui-select-container {\r
-       margin-top : 0px;\r
-       margin-bottom : 10px;\r
-       white-space : nowrap;\r
-}\r
-\r
-.ui-preview-checkbox-container {\r
-       display : inline-block;\r
-}\r
-\r
-.ui-checkbox {\r
-       margin-bottom:3px;\r
-       margin-left:5px;\r
-       margin-right:5px;\r
-       margin-top:0px;\r
-       vertical-align:middle;\r
-}\r
-\r
-input::-moz-focus-inner { border: 0; }\r
-\r
-.action-output-text {\r
-       margin-bottom : 5px;\r
-}\r
-\r
-button {\r
-       margin-right : 5px;\r
-}\r
-\r
+/* http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/ */
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, font, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td {
+       margin: 0;
+       padding: 0;
+       border: 0;
+       outline: 0;
+       font-weight: inherit;
+       font-style: inherit;
+       font-size: 100%;
+       font-family: inherit;
+       vertical-align: baseline;
+}
+/* remember to define focus styles! */
+:focus {
+       outline: 0;
+}
+body {
+       line-height: 1;
+       color: black;
+       background: white;
+}
+ol, ul {
+       list-style: none;
+}
+/* tables still need 'cellspacing="0"' in the markup */
+table {
+       border-collapse: separate;
+       border-spacing: 0;
+}
+caption, th, td {
+       text-align: left;
+       font-weight: normal;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+       content: "";
+}
+blockquote, q {
+       quotes: "" "";
+}
+/* end reset */
+
+/* -----------------------
+ *   Base
+ * -----------------------
+ */
+
+/* main container element for editor app */
+#pixastic-editor {
+       margin : 0;
+       position : absolute;
+       left : 0;
+       top : 0;
+       padding: 0px;
+       width: 100%;
+       height: 100%;
+       font-family : Helvetica,Arial,sans-serif;
+       overflow : hidden;
+       z-index : 10000000;
+} 
+
+
+/* -----------------------
+ *   Loading screen
+ * -----------------------
+ */
+
+/* container for loading screen */
+#loading-screen {
+       margin : 0;
+       position : absolute;
+       left : 0;
+       top : 0;
+       padding: 0px;
+       width: 100%;
+       height: 100%;
+       font-family : Helvetica,Arial,sans-serif;
+       overflow : hidden;
+       z-index : 10000000;
+       background-color : #111;
+       opacity : 0.9;
+       display : table;
+       text-align : center;
+} 
+
+/* container for spinner in loading screen */
+#loading-screen-cell {
+       display : table-cell;
+       vertical-align : middle;
+       text-align : center;
+}
+
+
+/* -----------------------
+ *   Misc
+ * -----------------------
+ */
+
+
+// UI error dialog
+.ui-dialog .error-dialog {
+       background-color : #544;
+}
+
+/* loading spinner */
+.spinner {
+       width : 31px;
+       height : 31px;
+       display : inline-block;
+       background: url(spinner.gif);
+       overflow : hidden;
+}
+
+canvas.display-canvas,
+canvas.undo-canvas {
+       /*
+       background : url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC1JREFUeNpiPHPmDAM2YGxsjFWciYFEMKqBGMD4//9/rBJnz54dDSX6aQAIMABCtQiAsDRF+wAAAABJRU5ErkJggg==');
+       */
+       background : url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC5JREFUeNpiPHPmTAMDHmBsbIxPmoGJgUIwasBgMICFUDyfPXt2NBCHvwEAAQYAICIGn294LYEAAAAASUVORK5CYII=');
+
+}
+
+.far-far-away {
+       position : absolute;
+       left : -9999px;
+       top : -9999px;
+}
+
+#powered-by-pixastic {
+       position : absolute;
+       bottom : 0px;
+       margin-bottom : 23px;
+       margin-left : 42px;
+}
+#powered-by-pixastic a {
+       font-size : 12px;
+       font-family : Helvetica,Arial,sans-serif;
+       letter-spacing : 0.1em;
+       color : rgb(100,100,100);
+       color : rgba(255,255,255,0.2);
+       text-decoration : none;
+}
+
+#powered-by-pixastic a:hover {
+       color : rgb(200,200,200);
+       color : rgba(255,255,255,0.7);
+       text-decoration : underline;
+}
+
+
+/* -----------------------
+ *   Skeleton structure
+ * -----------------------
+ */
+
+/* editor background underlay */
+#background {
+       background-color : #111;
+       opacity : 0.9;
+       width : 100%;
+       height : 100%;
+       position : absolute;
+       z-index : -1;
+}
+
+#image-area {
+       position : relative;
+       background-color : #222;
+       border : 1px solid #444;
+       width : 100%;
+       height : 100%;
+       -moz-box-sizing:border-box;
+       overflow : auto;
+       text-align : center;
+}
+
+#image-area-sub {
+}
+
+#image-container {
+}
+
+#image-overlay-container {
+       -moz-box-sizing:border-box;
+       width:100%;
+       height:100%;
+       position:absolute;
+       top:0;
+       left:0;
+}
+
+#image-overlay {
+}
+
+
+/* structure elements */
+#edit-ctr-1 {
+       position : absolute;
+       top : 0;
+       left : 0;
+       width : 100%;
+       height : 100%;
+}
+
+#edit-ctr-2 {
+       -moz-box-sizing : border-box;
+       box-sizing : border-box;
+       padding-left:40px;
+       padding-right:420px;
+       padding-top:70px;
+       padding-bottom : 40px;
+       height : 100%;
+       width : 100%;
+}
+
+
+/* main menu bar */
+#main-bar {
+       position : absolute;
+       width : 100%;
+       text-align : right;
+       margin-top : 20px;
+       margin-right : 30px;
+}
+
+/* area on the right with accordion widgets and undo bar */
+#controls-bar {
+       margin-right : -385px;
+       width : 372px;
+       float : right;
+       height : 100%;
+}
+
+/* accordion area */
+#action-bar {
+       padding : 10px;
+       width : 290px;
+       background-color : #222;
+       border : 1px solid #444;
+       -moz-box-sizing : border-box;
+       box-sizing : border-box;
+       height : 100%;
+       overflow-x : hidden;
+       overflow-y : auto;
+       float: right; 
+       position : relative;
+}
+
+#action-bar-overlay {
+       position : absolute;
+       z-index : 1000000;
+       width : 100%;
+       height : 100%;
+       left : 0;
+       top : 0;
+       background-color : #444;
+       opacity : 0.2;
+       display : none;
+}
+
+
+/* vertical bar with undo image states */
+#undo-bar {
+       -moz-box-sizing : border-box;
+       box-sizing : border-box;
+       background-color : #222;
+       border : 1px solid #444;
+       width: 70px; 
+       height: 100%;
+       overflow: hidden;
+       padding-top : 3px;
+}
+
+
+
+/* -----------------------
+ *   Main menu styles
+ * -----------------------
+ */
+
+.main-tab {
+       color : #999;
+       display : inline-block;
+       width : 150px;
+       text-transform : lowercase;
+       font-size : 22px;
+       cursor : pointer;
+       text-align : center;
+       text-decoration : none;
+       padding-top : 4px;
+       padding-bottom : 5px;
+       outline : 0;
+}
+
+.main-tab.hover {
+       color : white !important;
+}
+
+.main-tab.active {
+       color : white;
+}
+
+
+
+/* -----------------------
+ *   Undo list
+ * -----------------------
+ */
+
+
+.undo-canvas-small {
+       width : 60px;
+       height : 40px;
+       cursor : pointer;
+}
+
+.undo-link {
+       width : 60px;
+       height : 40px;
+       display : block;
+       margin : 4px;
+       cursor : pointer;
+       opacity : 0.8;
+}
+
+.undo-link.hover {
+       opacity : 1;
+}
+
+
+
+/* -----------------------
+ *   Action UI controls
+ * -----------------------
+ */
+
+
+.ui-slider-label, 
+.ui-checkbox-label, 
+.ui-textinput-label, 
+.ui-select-label {
+       width : 70px;
+       text-align : right;
+       margin-right : 5px;
+       display : inline-block;
+}
+
+.ui-textinput-label-right {
+       margin-left : 5px;
+}
+
+.ui-textinput {
+}
+
+.ui-numericinput {
+       width : 35px;
+}
+
+.ui-slider {
+       width : 125px;
+       display : inline-block;
+       margin-left : 3px;
+       background-color : #222;
+}
+
+.ui-slider-value {
+       font-size : 11px;
+       width : 25px;
+       display : inline-block;
+       margin-left : 10px;
+}
+
+.ui-action-output {
+       margin-bottom : 10px;
+}
+
+.ui-accordion .ui-accordion-content-active {
+       font-size : 11px;
+       overflow : hidden;
+}
+
+.ui-slider-horizontal {
+}
+
+.ui-slider-container, 
+.ui-checkbox-container, 
+.ui-textinput-container, 
+.ui-select-container {
+       margin-top : 0px;
+       margin-bottom : 10px;
+       white-space : nowrap;
+}
+
+.ui-preview-checkbox-container {
+       display : inline-block;
+}
+
+.ui-checkbox {
+       margin-bottom:3px;
+       margin-left:5px;
+       margin-right:5px;
+       margin-top:0px;
+       vertical-align:middle;
+}
+
+input::-moz-focus-inner { border: 0; }
+
+.action-output-text {
+       margin-bottom : 5px;
+}
+
+button {
+       margin-right : 5px;
+}
+
index a0a20ba..6b267ac 100644 (file)
-(function($) {\r
-\r
-       var PE = PixasticEditor;\r
-\r
-       function makeSlider(label, id, min, max, step, defaultVal, onChange) {\r
-               var $ctr = $j("<div></div>", PE.getDocument())\r
-                       .addClass("ui-slider-container");\r
-\r
-               var $label = $j("<label></label>", PE.getDocument())\r
-                       .addClass("ui-slider-label")\r
-                       .attr("for", "input-slider-" + id)\r
-                       .html(label + ":")\r
-                       .appendTo($ctr);\r
-\r
-               var $value = $j("<div></div>", PE.getDocument())\r
-                       .addClass("ui-slider-value")\r
-                       .html(defaultVal());\r
-\r
-               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
-                       .attr("id", "input-hidden-" + id)\r
-                       .val(defaultVal())\r
-                       .appendTo($ctr);\r
-\r
-               var performOnChange = true;\r
-\r
-               var $slider = $j("<div class='ui-slider'><div class='ui-slider-handle'></div><div class='ui-slider-range'></div></div>", PE.getDocument())\r
-                       .appendTo($ctr)\r
-                       .attr("id", "input-slider-" + id)\r
-                       .slider({\r
-                               slide: function() {\r
-                                       $value.html($j(this).slider("value"));\r
-                                       $valueField.val($j(this).slider("value"));\r
-                               },\r
-                               change : function() {\r
-                                       $value.html($j(this).slider("value"));\r
-                                       $valueField.val($j(this).slider("value"));\r
-                                       if (onChange && performOnChange)\r
-                                               onChange();\r
-                               },\r
-                               min : min,\r
-                               max : max,\r
-                               step : step,\r
-                               value : defaultVal()\r
-                       });\r
-\r
-               $value.appendTo($ctr);\r
-\r
-               return {\r
-                       container : $ctr,\r
-                       label : $label,\r
-                       slider : $slider,\r
-                       valueText : $value,\r
-                       valueField : $valueField,\r
-                       reset : function() {\r
-                               performOnChange = false;\r
-                               $value.html(defaultVal());\r
-                               $valueField.val(defaultVal());\r
-                               $slider.slider("value", defaultVal());\r
-                               performOnChange = true;\r
-                       }\r
-               };\r
-       }\r
-\r
-       function makeCheckbox(label, id, defaultVal, onChange) {\r
-               var $ctr = $j("<div></div>", PE.getDocument())\r
-                       .addClass("ui-checkbox-container");\r
-\r
-               var $label = $j("<label></label>", PE.getDocument())\r
-                       .addClass("ui-checkbox-label")\r
-                       .attr("for", "input-checkbox-" + id)\r
-                       .html(label + ":")\r
-                       .appendTo($ctr);\r
-\r
-               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
-                       .attr("id", "input-hidden-" + id)\r
-                       .val(defaultVal())\r
-                       .appendTo($ctr);\r
-\r
-               var performOnChange = true;\r
-\r
-               var $checkbox = $j("<input type=\"checkbox\"></input>", PE.getDocument())\r
-                       .addClass("ui-checkbox")\r
-                       .attr("id", "input-checkbox-" + id)\r
-                       .attr("checked", defaultVal())\r
-                       .appendTo($ctr)\r
-                       .change(function() {\r
-                               $valueField.val(this.checked);\r
-                               if (onChange && performOnChange)\r
-                                       onChange();\r
-                       });\r
-\r
-               return {\r
-                       container : $ctr,\r
-                       label : $label,\r
-                       checkbox : $checkbox,\r
-                       valueField : $valueField,\r
-                       reset : function() {\r
-                               performOnChange = false;\r
-                               $checkbox.attr("checked", defaultVal());\r
-                               $valueField.val(defaultVal());\r
-                               performOnChange = true;\r
-                       }\r
-               };\r
-       }\r
-\r
-       function makeSelect(label, id, values, defaultVal, onChange) {\r
-               var $ctr = $j("<div></div>", PE.getDocument())\r
-                       .addClass("ui-select-container");\r
-\r
-               var $label = $j("<label></label>", PE.getDocument())\r
-                       .addClass("ui-checkbox-label")\r
-                       .attr("for", "input-checkbox-" + id)\r
-                       .html(label + ":")\r
-                       .appendTo($ctr);\r
-\r
-               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
-                       .attr("id", "input-hidden-" + id)\r
-                       .val(defaultVal())\r
-                       .appendTo($ctr);\r
-\r
-               var selectHtml = "<select>";\r
-               for (var i=0;i<values.length;i++) {\r
-                       selectHtml += "<option value='" + values[i].value + "' " \r
-                               + (defaultVal() == values[i].value ? "selected" : "") \r
-                               + ">" + values[i].name + "</option>";\r
-               }\r
-               selectHtml += "</select>";\r
-\r
-               var $select = $j(selectHtml).appendTo($ctr);\r
-\r
-               var performOnChange = true;\r
-\r
-               $select.change(\r
-                       function() {\r
-                               $valueField.val(this.options[this.selectedIndex].value);\r
-                               if (onChange && performOnChange)\r
-                                       onChange();\r
-                       }\r
-               );\r
-\r
-               return {\r
-                       container : $ctr,\r
-                       label : $label,\r
-                       select : $select,\r
-                       valueField : $valueField,\r
-                       reset : function() {\r
-                               performOnChange = false;\r
-                               var defVal = defaultVal();\r
-                               $select.val(defVal);\r
-                               $valueField.val(defVal);\r
-                               performOnChange = true;\r
-                       }\r
-               };\r
-       }\r
-\r
-       function makeNumericInput(label, labelRight, id, min, max, step, defaultVal, onChange) {\r
-               var $ctr = $j("<div></div>", PE.getDocument())\r
-                       .addClass("ui-textinput-container");\r
-\r
-               var $label = $j("<label></label>", PE.getDocument())\r
-                       .addClass("ui-textinput-label")\r
-                       .attr("for", "input-numeric-" + id)\r
-                       .html(label + ":")\r
-                       .appendTo($ctr);\r
-\r
-               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
-                       .attr("id", "input-hidden-" + id)\r
-                       .val(defaultVal())\r
-                       .appendTo($ctr);\r
-\r
-               var performOnChange = true;\r
-\r
-               function setVal(val) {\r
-                       val = Math.min(max, val);\r
-                       val = Math.max(min, val);\r
-                       $textInput.val(val);\r
-                       $valueField.val(val);\r
-               }\r
-\r
-               var $textInput = $j("<input type=\"text\"></input>", PE.getDocument())\r
-                       .addClass("ui-textinput")\r
-                       .addClass("ui-numericinput")\r
-                       .appendTo($ctr)\r
-                       .val(defaultVal())\r
-                       .attr("id", "input-numeric-" + id)\r
-                       .change(function() {\r
-                               var val = parseFloat(this.value);\r
-                               setVal(val);\r
-                               if (onChange && performOnChange)\r
-                                       onChange();\r
-                       })\r
-                       .keydown(function(e) {\r
-                               var val = parseFloat($j(this).val());\r
-                               if (e.keyCode == 38) { // up\r
-                                       setVal(val + step);\r
-                               }\r
-                               if (e.keyCode == 40) { // down\r
-                                       setVal(val - step);\r
-                               }\r
-                       });\r
-\r
-               if (labelRight) {\r
-                       var $labelRight = $j("<label></label>", PE.getDocument())\r
-                               .addClass("ui-textinput-label-right")\r
-                               .html(labelRight)\r
-                               .appendTo($ctr);\r
-               }\r
-\r
-               return {\r
-                       container : $ctr,\r
-                       label : $label,\r
-                       textinput : $textInput,\r
-                       valueField : $valueField,\r
-                       reset : function() {\r
-                               performOnChange = false;\r
-                               setVal(defaultVal());\r
-                               performOnChange = true;\r
-                       }\r
-               };\r
-       }\r
-\r
-       function makeButton(text) {\r
-               var $button = $j("<button></button>", PE.getDocument()).html(text);\r
-               return $button;\r
-       }\r
-\r
-\r
-       PE.UI = {\r
-               makeSlider : makeSlider,\r
-               makeCheckbox : makeCheckbox,\r
-               makeNumericInput : makeNumericInput,\r
-               makeSelect : makeSelect,\r
-               makeButton : makeButton\r
-       }\r
-\r
-})(PixasticEditor.jQuery);\r
-\r
+(function($) {
+
+       var PE = PixasticEditor;
+
+       function makeSlider(label, id, min, max, step, defaultVal, onChange) {
+               var $ctr = $j("<div></div>", PE.getDocument())
+                       .addClass("ui-slider-container");
+
+               var $label = $j("<label></label>", PE.getDocument())
+                       .addClass("ui-slider-label")
+                       .attr("for", "input-slider-" + id)
+                       .html(label + ":")
+                       .appendTo($ctr);
+
+               var $value = $j("<div></div>", PE.getDocument())
+                       .addClass("ui-slider-value")
+                       .html(defaultVal());
+
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())
+                       .attr("id", "input-hidden-" + id)
+                       .val(defaultVal())
+                       .appendTo($ctr);
+
+               var performOnChange = true;
+
+               var $slider = $j("<div class='ui-slider'><div class='ui-slider-handle'></div><div class='ui-slider-range'></div></div>", PE.getDocument())
+                       .appendTo($ctr)
+                       .attr("id", "input-slider-" + id)
+                       .slider({
+                               slide: function() {
+                                       $value.html($j(this).slider("value"));
+                                       $valueField.val($j(this).slider("value"));
+                               },
+                               change : function() {
+                                       $value.html($j(this).slider("value"));
+                                       $valueField.val($j(this).slider("value"));
+                                       if (onChange && performOnChange)
+                                               onChange();
+                               },
+                               min : min,
+                               max : max,
+                               step : step,
+                               value : defaultVal()
+                       });
+
+               $value.appendTo($ctr);
+
+               return {
+                       container : $ctr,
+                       label : $label,
+                       slider : $slider,
+                       valueText : $value,
+                       valueField : $valueField,
+                       reset : function() {
+                               performOnChange = false;
+                               $value.html(defaultVal());
+                               $valueField.val(defaultVal());
+                               $slider.slider("value", defaultVal());
+                               performOnChange = true;
+                       }
+               };
+       }
+
+       function makeCheckbox(label, id, defaultVal, onChange) {
+               var $ctr = $j("<div></div>", PE.getDocument())
+                       .addClass("ui-checkbox-container");
+
+               var $label = $j("<label></label>", PE.getDocument())
+                       .addClass("ui-checkbox-label")
+                       .attr("for", "input-checkbox-" + id)
+                       .html(label + ":")
+                       .appendTo($ctr);
+
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())
+                       .attr("id", "input-hidden-" + id)
+                       .val(defaultVal())
+                       .appendTo($ctr);
+
+               var performOnChange = true;
+
+               var $checkbox = $j("<input type=\"checkbox\"></input>", PE.getDocument())
+                       .addClass("ui-checkbox")
+                       .attr("id", "input-checkbox-" + id)
+                       .attr("checked", defaultVal())
+                       .appendTo($ctr)
+                       .change(function() {
+                               $valueField.val(this.checked);
+                               if (onChange && performOnChange)
+                                       onChange();
+                       });
+
+               return {
+                       container : $ctr,
+                       label : $label,
+                       checkbox : $checkbox,
+                       valueField : $valueField,
+                       reset : function() {
+                               performOnChange = false;
+                               $checkbox.attr("checked", defaultVal());
+                               $valueField.val(defaultVal());
+                               performOnChange = true;
+                       }
+               };
+       }
+
+       function makeSelect(label, id, values, defaultVal, onChange) {
+               var $ctr = $j("<div></div>", PE.getDocument())
+                       .addClass("ui-select-container");
+
+               var $label = $j("<label></label>", PE.getDocument())
+                       .addClass("ui-checkbox-label")
+                       .attr("for", "input-checkbox-" + id)
+                       .html(label + ":")
+                       .appendTo($ctr);
+
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())
+                       .attr("id", "input-hidden-" + id)
+                       .val(defaultVal())
+                       .appendTo($ctr);
+
+               var selectHtml = "<select>";
+               for (var i=0;i<values.length;i++) {
+                       selectHtml += "<option value='" + values[i].value + "' " 
+                               + (defaultVal() == values[i].value ? "selected" : "") 
+                               + ">" + values[i].name + "</option>";
+               }
+               selectHtml += "</select>";
+
+               var $select = $j(selectHtml).appendTo($ctr);
+
+               var performOnChange = true;
+
+               $select.change(
+                       function() {
+                               $valueField.val(this.options[this.selectedIndex].value);
+                               if (onChange && performOnChange)
+                                       onChange();
+                       }
+               );
+
+               return {
+                       container : $ctr,
+                       label : $label,
+                       select : $select,
+                       valueField : $valueField,
+                       reset : function() {
+                               performOnChange = false;
+                               var defVal = defaultVal();
+                               $select.val(defVal);
+                               $valueField.val(defVal);
+                               performOnChange = true;
+                       }
+               };
+       }
+
+       function makeNumericInput(label, labelRight, id, min, max, step, defaultVal, onChange) {
+               var $ctr = $j("<div></div>", PE.getDocument())
+                       .addClass("ui-textinput-container");
+
+               var $label = $j("<label></label>", PE.getDocument())
+                       .addClass("ui-textinput-label")
+                       .attr("for", "input-numeric-" + id)
+                       .html(label + ":")
+                       .appendTo($ctr);
+
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())
+                       .attr("id", "input-hidden-" + id)
+                       .val(defaultVal())
+                       .appendTo($ctr);
+
+               var performOnChange = true;
+
+               function setVal(val) {
+                       val = Math.min(max, val);
+                       val = Math.max(min, val);
+                       $textInput.val(val);
+                       $valueField.val(val);
+               }
+
+               var $textInput = $j("<input type=\"text\"></input>", PE.getDocument())
+                       .addClass("ui-textinput")
+                       .addClass("ui-numericinput")
+                       .appendTo($ctr)
+                       .val(defaultVal())
+                       .attr("id", "input-numeric-" + id)
+                       .change(function() {
+                               var val = parseFloat(this.value);
+                               setVal(val);
+                               if (onChange && performOnChange)
+                                       onChange();
+                       })
+                       .keydown(function(e) {
+                               var val = parseFloat($j(this).val());
+                               if (e.keyCode == 38) { // up
+                                       setVal(val + step);
+                               }
+                               if (e.keyCode == 40) { // down
+                                       setVal(val - step);
+                               }
+                       });
+
+               if (labelRight) {
+                       var $labelRight = $j("<label></label>", PE.getDocument())
+                               .addClass("ui-textinput-label-right")
+                               .html(labelRight)
+                               .appendTo($ctr);
+               }
+
+               return {
+                       container : $ctr,
+                       label : $label,
+                       textinput : $textInput,
+                       valueField : $valueField,
+                       reset : function() {
+                               performOnChange = false;
+                               setVal(defaultVal());
+                               performOnChange = true;
+                       }
+               };
+       }
+
+       function makeButton(text) {
+               var $button = $j("<button></button>", PE.getDocument()).html(text);
+               return $button;
+       }
+
+
+       PE.UI = {
+               makeSlider : makeSlider,
+               makeCheckbox : makeCheckbox,
+               makeNumericInput : makeNumericInput,
+               makeSelect : makeSelect,
+               makeButton : makeButton
+       }
+
+})(PixasticEditor.jQuery);
+
index 03f50b7..ef648f6 100644 (file)
-(function($) {\r
-\r
-var PE = PixasticEditor;\r
-\r
-PE.UI.data = {\r
-       tabs : [\r
-               {\r
-                       title : "Reshape",\r
-                       id : "reshape",\r
-                       actions : [\r
-                               {\r
-                                       title : "Resize",\r
-                                       id : "resize",\r
-                                       isAction : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Enter new dimensions below."\r
-                                               },\r
-                                               {\r
-                                                       label : "Width",\r
-                                                       labelRight : "px",\r
-                                                       option : "width",\r
-                                                       type : "number", \r
-                                                       range : [1,10000], \r
-                                                       step : 1,\r
-                                                       defaultValue : function() { return PE.getImageWidth(); },\r
-                                                       ui : "text"\r
-                                               },\r
-                                               {\r
-                                                       label : "Height",\r
-                                                       labelRight : "px",\r
-                                                       option : "height",\r
-                                                       type : "number", \r
-                                                       range : [1,10000], \r
-                                                       step : 1,\r
-                                                       defaultValue : function() { return PE.getImageHeight(); },\r
-                                                       ui : "text"\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Crop",\r
-                                       id : "crop",\r
-                                       isAction : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Enter new crop values below or use mouse to select crop area."\r
-                                               },\r
-                                               {\r
-                                                       label : "X",\r
-                                                       labelRight : "px",\r
-                                                       option : "left",\r
-                                                       type : "number", \r
-                                                       range : [0,10000], \r
-                                                       step : 1,\r
-                                                       defaultValue : 0,\r
-                                                       ui : "text"\r
-                                               },\r
-                                               {\r
-                                                       label : "Y",\r
-                                                       labelRight : "px",\r
-                                                       option : "top",\r
-                                                       type : "number", \r
-                                                       range : [0,10000], \r
-                                                       step : 1,\r
-                                                       defaultValue : 0,\r
-                                                       ui : "text"\r
-                                               },\r
-                                               {\r
-                                                       label : "Width",\r
-                                                       labelRight : "px",\r
-                                                       option : "width",\r
-                                                       type : "number", \r
-                                                       range : [1,10000], \r
-                                                       step : 1,\r
-                                                       defaultValue : function() { return PE.getImageWidth(); },\r
-                                                       ui : "text"\r
-                                               },\r
-                                               {\r
-                                                       label : "Height",\r
-                                                       labelRight : "px",\r
-                                                       option : "height",\r
-                                                       type : "number", \r
-                                                       range : [1,10000], \r
-                                                       step : 1,\r
-                                                       defaultValue : function() { return PE.getImageHeight(); },\r
-                                                       ui : "text"\r
-                                               }\r
-                                       ],\r
-                                       onactivate : function() {\r
-                                               var $canvas = PE.getDisplayCanvas();\r
-                                               var onchange = function(c) {\r
-                                                       var doc = PE.getDocument();\r
-                                                       $j("#input-numeric-crop-left", doc).val(c.x).change();\r
-                                                       $j("#input-numeric-crop-top", doc).val(c.y).change();\r
-                                                       $j("#input-numeric-crop-width", doc).val(c.w).change();\r
-                                                       $j("#input-numeric-crop-height", doc).val(c.h).change();\r
-                                                       $j("#input-hidden-crop-left", doc).val(c.x).change();\r
-                                                       $j("#input-hidden-crop-top", doc).val(c.y).change();\r
-                                                       $j("#input-hidden-crop-width", doc).val(c.w).change();\r
-                                                       $j("#input-hidden-crop-height", doc).val(c.h).change();\r
-                                               }\r
-                                               $canvas.data("Jcrop-onchange", onchange);\r
-                                               $canvas.Jcrop({onChange:onchange}, PE.getDocument());\r
-                                       },\r
-                                       ondeactivate : function() {\r
-                                               var $canvas = PE.getDisplayCanvas();\r
-                                               if ($canvas.data("Jcrop") && $canvas.data("Jcrop").destroy)\r
-                                                       $canvas.data("Jcrop").destroy();\r
-                                       },\r
-                                       onafteraction : function(action, isPreview) {\r
-                                               action.ondeactivate();\r
-                                               action.onactivate();\r
-                                               /*\r
-                                               var $canvas = PE.getDisplayCanvas();\r
-                                               if ($canvas.data("Jcrop") && $canvas.data("Jcrop").destroy)\r
-                                                       $canvas.data("Jcrop").destroy();\r
-                                               var onchange = $canvas.data("Jcrop-onchange");\r
-                                               $canvas.Jcrop({onChange:onchange});\r
-                                               */\r
-                                       }\r
-                               },\r
-                               {\r
-                                       title : "Rotate",\r
-                                       id : "rotate",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       forcePreview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Enter the angle (-180&deg; to 180&deg;) you want to rotate the picture. Use negative values for clockwise rotation, positive for counterclockwise."\r
-                                               },\r
-                                               {\r
-                                                       label : "Angle",\r
-                                                       labelRight : "&deg;",\r
-                                                       option : "angle",\r
-                                                       type : "number", \r
-                                                       range : [-180,180], \r
-                                                       step : 1,\r
-                                                       defaultValue : 0,\r
-                                                       ui : "text"\r
-                                               }\r
-                                       ],\r
-                                       onactivate : function() {\r
-                                               var doc = PE.getDocument();\r
-                                               var $displayCanvas = PE.getDisplayCanvas();\r
-                                               var dim = Math.min($displayCanvas.attr("height"), 200);\r
-                                               var $canvas = $j("<canvas></canvas>", doc);\r
-                                               PE.getOverlay().append($canvas);\r
-\r
-                                               $canvas.attr("width", dim);\r
-                                               $canvas.attr("height", dim);\r
-                                               $canvas.width(dim);\r
-                                               $canvas.height(dim);\r
-\r
-                                               $canvas.css("marginTop", (($displayCanvas.attr("height") - dim) * 0.5) + "px");\r
-\r
-                                               var lineWidth = 20;\r
-                                               var radius = dim/2 - lineWidth;\r
-                                               if (radius < 1) radius = 1;\r
-\r
-                                               var ctx = $canvas.get(0).getContext("2d");\r
-                                               ctx.beginPath()\r
-                                               ctx.arc(dim/2, dim/2, radius, 0, Math.PI*2, true);\r
-                                               ctx.closePath();\r
-                                               ctx.fillStyle = "rgba(200,200,200,0.2)";\r
-                                               ctx.fill();\r
-                                               ctx.strokeStyle = "rgba(200,200,200,0.5)";\r
-                                               ctx.lineWidth = 20;\r
-                                               ctx.stroke();\r
-\r
-                                               $j("#image-area", doc).css("cursor", "move");\r
-\r
-                                               $overlay = PE.getOverlay();\r
-\r
-                                               $canvas.get(0).ondragstart = function() {return false;}\r
-                                               $canvas.get(0).onselectstart = function() {return false;}\r
-\r
-                                               var mx = 0, my = 0;\r
-                                               var startMouseAngle = 0;\r
-                                               var startAngle = 0;\r
-                                               var deltaAngle = 0;\r
-                                               var angle = 0;\r
-\r
-                                               var mouseIsDown = false;\r
-                                               var onmousedown = function(e) {\r
-                                                       mouseIsDown = true;\r
-                                                       var offset = $displayCanvas.offset();\r
-                                                       mx = (e.pageX - offset.left) - $displayCanvas.attr("width")*0.5;\r
-                                                       my = (e.pageY - offset.top) - $displayCanvas.attr("height")*0.5;\r
-                                                       startMouseAngle = Math.atan2(my, mx);\r
-                                                       startAngle = parseInt($j("#input-numeric-rotate-angle", doc).val(), 10) * Math.PI / 180;\r
-                                               }\r
-                                               var onmousemove = function(e) {\r
-                                                       if (!mouseIsDown) return;\r
-\r
-                                                       var offset = $displayCanvas.offset();\r
-                                                       mx = (e.pageX - offset.left) - $displayCanvas.attr("width")*0.5;\r
-                                                       my = (e.pageY - offset.top) - $displayCanvas.attr("height")*0.5;\r
-                                                       deltaAngle = Math.atan2(my, mx) - startMouseAngle;\r
-                                                       angle = startAngle - deltaAngle;\r
-                                                       if (angle < -Math.PI) angle += 2*Math.PI;\r
-                                                       if (angle > Math.PI) angle -= 2*Math.PI;\r
-                                                       $j("#input-numeric-rotate-angle", doc).val(Math.round(angle * 180 / Math.PI));\r
-                                                       $j("#input-numeric-rotate-angle", doc).change();\r
-                                               }\r
-                                               var onmouseup = function() {\r
-                                                       mouseIsDown = false;\r
-                                               }\r
-\r
-                                               $j("#image-area", doc).bind("mousedown", onmousedown);\r
-                                               $j("#image-area", doc).bind("mousemove", onmousemove);\r
-                                               $j("#image-area", doc).bind("mouseup", onmouseup);\r
-                                               $canvas.data("onmousedown", onmousedown);\r
-                                               $canvas.data("onmousemove", onmousemove);\r
-                                               $canvas.data("onmouseup", onmouseup);\r
-                                               $displayCanvas.data("rotateCanvas", $canvas);\r
-                                       },\r
-                                       ondeactivate : function() {\r
-                                               var doc = PE.getDocument();\r
-                                               var $displayCanvas = PE.getDisplayCanvas();\r
-                                               $overlay = PE.getOverlay();\r
-                                               $j("#image-area", doc).css("cursor", "default");\r
-\r
-                                               var $canvas = $displayCanvas.data("rotateCanvas");\r
-\r
-                                               $j("#image-area", doc).unbind("mousedown", $canvas.data("onmousedown"));\r
-                                               $j("#image-area", doc).unbind("mousemove", $canvas.data("onmousemove"));\r
-                                               $j("#image-area", doc).unbind("mouseup", $canvas.data("onmouseup"));\r
-                                               $displayCanvas.removeData("rotateCanvas");\r
-                                               $canvas.remove();\r
-                                       },\r
-                                       onafteraction : function(action, isPreview) {\r
-                                               if (!isPreview) { // rebuild the rotate widget\r
-                                                       action.ondeactivate();\r
-                                                       action.onactivate();\r
-                                               }\r
-                                       },\r
-                                       onoverlayupdate : function() {\r
-                                               var $canvas = PE.getDisplayCanvas().data("rotateCanvas");\r
-                                               if ($canvas) {\r
-                                                       $canvas.css("marginTop", ((PE.getDisplayCanvas().get(0).height - $canvas.get(0).height) * 0.5) + "px");\r
-                                               }\r
-                                       }\r
-                               },\r
-                               {\r
-                                       title : "Flip",\r
-                                       id : "flip",\r
-                                       isAction : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       label : "Axis",\r
-                                                       option : "axis",\r
-                                                       type : "string", \r
-                                                       values : [\r
-                                                               {name:"Horizontal", value:"horizontal"},\r
-                                                               {name:"Vertical", value:"vertical"}\r
-                                                       ],\r
-                                                       defaultValue : "vertical",\r
-                                                       ui : "select"\r
-                                               }\r
-                                       ]\r
-                               }\r
-                       ]\r
-               },\r
-               {\r
-                       title : "Develop",\r
-                       id : "develop",\r
-                       actions : [\r
-                               {\r
-                                       title : "Brightness & Contrast",\r
-                                       id : "brightness",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Use the sliders below to adjust the brightness and/or contrast of the image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Brightness",\r
-                                                       option : "brightness",\r
-                                                       type : "number", \r
-                                                       range : [-100,100], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               },\r
-                                               {\r
-                                                       label : "Contrast",\r
-                                                       option : "contrast",\r
-                                                       type : "number", \r
-                                                       range : [-1,1], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Legacy mode",\r
-                                                       option : "legacy",\r
-                                                       type : "boolean", \r
-                                                       defaultValue : false,\r
-                                                       ui : "checkbox"\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Hue/Saturation/Lightness",\r
-                                       id : "hsl",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Use the sliders below to adjust the hue, saturation and/or lightness of the image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Hue",\r
-                                                       option : "hue",\r
-                                                       type : "number", \r
-                                                       range : [-180,180], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               },\r
-                                               {\r
-                                                       label : "Saturation",\r
-                                                       option : "saturation",\r
-                                                       type : "number", \r
-                                                       range : [-100,100], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               },\r
-                                               {\r
-                                                       label : "Lightness",\r
-                                                       option : "lightness",\r
-                                                       type : "number", \r
-                                                       range : [-100,100], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Adjust colors",\r
-                                       id : "coloradjust",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Use the sliders below to shift the R, G and B channels of the image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Red",\r
-                                                       option : "red",\r
-                                                       type : "number", \r
-                                                       range : [-1,1], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Green",\r
-                                                       option : "green",\r
-                                                       type : "number", \r
-                                                       range : [-1,1], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Blue",\r
-                                                       option : "blue",\r
-                                                       type : "number", \r
-                                                       range : [-1,1], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Desaturate",\r
-                                       id : "desaturate",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "This will desaturate the image. Select \"Use average\" to use the average value of the R, G and B channels rather than the default mix of 30% red, 59% green and 11% blue."\r
-                                               },\r
-                                               {\r
-                                                       label : "Use average",\r
-                                                       option : "average",\r
-                                                       type : "boolean", \r
-                                                       defaultValue : false,\r
-                                                       ui : "checkbox"\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Sepia toning",\r
-                                       id : "sepia",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Applies a sepia toning effect to the image."\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Invert",\r
-                                       id : "invert",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "This will invert the colors of the image."\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Lighten",\r
-                                       id : "lighten",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Use the slider below to lighten or darken the image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Amount",\r
-                                                       option : "amount",\r
-                                                       type : "number", \r
-                                                       range : [-1,1], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Unsharp mask",\r
-                                       id : "unsharpmask",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Use the sliders below to adjust the unsharp mask parameters."\r
-                                               },\r
-                                               {\r
-                                                       label : "Amount",\r
-                                                       option : "amount",\r
-                                                       type : "number", \r
-                                                       range : [0,500], \r
-                                                       defaultValue : 200,\r
-                                                       ui : "slider",\r
-                                                       step : 2\r
-                                               },\r
-                                               {\r
-                                                       label : "Radius",\r
-                                                       option : "radius",\r
-                                                       type : "number", \r
-                                                       range : [0,5], \r
-                                                       defaultValue : 2,\r
-                                                       ui : "slider",\r
-                                                       step : 0.1\r
-                                               },\r
-                                               {\r
-                                                       label : "Threshold",\r
-                                                       option : "amount",\r
-                                                       type : "number", \r
-                                                       range : [0,255], \r
-                                                       defaultValue : 25,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               }\r
-                                       ]\r
-                               }\r
-\r
-                       ]\r
-               },\r
-               {\r
-                       title : "Effects",\r
-                       id : "effects",\r
-                       actions : [\r
-                               {\r
-                                       title : "Blur",\r
-                                       id : "blurfast",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Use the slider to set the blur amount."\r
-                                               },\r
-                                               {\r
-                                                       label : "Amount",\r
-                                                       option : "amount",\r
-                                                       type : "number", \r
-                                                       range : [0,1], \r
-                                                       defaultValue : 0.5,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               }\r
-                                       ]\r
-\r
-                               },\r
-                               {\r
-                                       title : "Edge detection",\r
-                                       id : "edges",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Performs edge detection on the image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Greyscale",\r
-                                                       option : "mono",\r
-                                                       type : "boolean", \r
-                                                       defaultValue : false,\r
-                                                       ui : "checkbox"\r
-                                               },\r
-                                               {\r
-                                                       label : "Invert",\r
-                                                       option : "invert",\r
-                                                       type : "boolean", \r
-                                                       defaultValue : false,\r
-                                                       ui : "checkbox"\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Emboss",\r
-                                       id : "emboss",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Adds an emboss-like effect to the image. Use the controls below to control the appearance of the effect. Choose \"Blend\" to blend the effect with the original image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Strength",\r
-                                                       option : "strength",\r
-                                                       type : "number", \r
-                                                       range : [0,10], \r
-                                                       defaultValue : 1,\r
-                                                       ui : "slider",\r
-                                                       step : 0.1\r
-                                               },\r
-                                               {\r
-                                                       label : "Grey level",\r
-                                                       option : "greyLevel",\r
-                                                       type : "number", \r
-                                                       range : [0,255], \r
-                                                       defaultValue : 180,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               },\r
-                                               {\r
-                                                       label : "Direction",\r
-                                                       option : "direction",\r
-                                                       type : "string", \r
-                                                       values : [\r
-                                                               {name:"Top left", value:"topleft"},\r
-                                                               {name:"Top", value:"top"},\r
-                                                               {name:"Top right", value:"topright"},\r
-                                                               {name:"Right", value:"right"},\r
-                                                               {name:"Bottom right", value:"bottomright"},\r
-                                                               {name:"Bottom", value:"bottom"},\r
-                                                               {name:"Bottom left", value:"bottomleft"},\r
-                                                               {name:"Left", value:"left"}\r
-                                                       ],\r
-                                                       defaultValue : "topleft",\r
-                                                       ui : "select"\r
-                                               },\r
-                                               {\r
-                                                       label : "Blend",\r
-                                                       option : "blend",\r
-                                                       type : "boolean", \r
-                                                       defaultValue : false,\r
-                                                       ui : "checkbox"\r
-                                               }\r
-                                       ]\r
-\r
-                               },\r
-                               {\r
-                                       title : "Glow",\r
-                                       id : "glow",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Creates a glowing effect on the image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Amount",\r
-                                                       option : "amount",\r
-                                                       type : "number", \r
-                                                       range : [0,1], \r
-                                                       defaultValue : 0.5,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Radius",\r
-                                                       option : "radius",\r
-                                                       type : "number", \r
-                                                       range : [0,1], \r
-                                                       defaultValue : 0.5,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Add noise",\r
-                                       id : "noise",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Add random noise to the image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Amount",\r
-                                                       option : "amount",\r
-                                                       type : "number", \r
-                                                       range : [0,1], \r
-                                                       defaultValue : 0.5,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Strength",\r
-                                                       option : "strength",\r
-                                                       type : "number", \r
-                                                       range : [0,1], \r
-                                                       defaultValue : 0.5,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Greyscale",\r
-                                                       option : "mono",\r
-                                                       type : "boolean", \r
-                                                       defaultValue : false,\r
-                                                       ui : "checkbox"\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Remove noise",\r
-                                       id : "removenoise",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Attempts to remove noise from the image. Works best for getting rid of single pixels that stand out."\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Pointillize",\r
-                                       id : "pointillize",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Paints the picture with circular points."\r
-                                               },\r
-                                               {\r
-                                                       label : "Point radius",\r
-                                                       option : "radius",\r
-                                                       type : "number", \r
-                                                       range : [1,50], \r
-                                                       defaultValue : 5,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               },\r
-                                               {\r
-                                                       label : "Density",\r
-                                                       option : "density",\r
-                                                       type : "number", \r
-                                                       range : [0,5], \r
-                                                       defaultValue : 1,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Noise",\r
-                                                       option : "noise",\r
-                                                       type : "number", \r
-                                                       range : [0,2], \r
-                                                       defaultValue : 1,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Transparent",\r
-                                                       option : "transparent",\r
-                                                       type : "boolean", \r
-                                                       defaultValue : false,\r
-                                                       ui : "checkbox"\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Posterize",\r
-                                       id : "posterize",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Reduces the number of colours to a specified number of levels."\r
-                                               },\r
-                                               {\r
-                                                       label : "Levels",\r
-                                                       option : "levels",\r
-                                                       type : "number", \r
-                                                       range : [1,32], \r
-                                                       defaultValue : 5,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Solarize",\r
-                                       id : "solarize",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Applies a solarize effect to the image."\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Mosaic",\r
-                                       id : "mosaic",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Creates a pixelated look."\r
-                                               },\r
-                                               {\r
-                                                       label : "Block size",\r
-                                                       option : "blockSize",\r
-                                                       type : "number", \r
-                                                       range : [1,100], \r
-                                                       defaultValue : 5,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               }\r
-                                       ]\r
-                               }\r
-\r
-\r
-                       ]\r
-               },\r
-               {\r
-                       title : "Done",\r
-                       id : "done",\r
-                       actions : [\r
-                               {\r
-                                       title : "Save to page",\r
-                                       id : "savepage",\r
-                                       content : function($ctr) {\r
-                                               var doc = PE.getDocument();\r
-                                               $j("<div></div>", doc)\r
-                                                       .addClass("action-output-text")\r
-                                                       .html("This will save the image to the page.")\r
-                                                       .appendTo($ctr);\r
-\r
-                                               var $buttonCtr = $j("<div></div>", doc).appendTo($ctr);\r
-                                               var $saveButton = $j("<button></button>", doc)\r
-                                                       .html("Save image")\r
-                                                       .appendTo($buttonCtr)\r
-                                                       .click(function() {\r
-                                                               PE.saveToPage();\r
-                                                       });\r
-\r
-                                       }\r
-                               },\r
-                               {\r
-                                       title : "Save to file",\r
-                                       id : "savefile",\r
-                                       content : function(ctr) {\r
-                                               var doc = PE.getDocument();\r
-                                               $j("<div></div>", doc)\r
-                                                       .addClass("action-output-text")\r
-                                                       .html("This will save the image to your local computer.")\r
-                                                       .appendTo(ctr);\r
-\r
-                                               var formats = PE.validSaveFormats();\r
-\r
-                                               var selectHtml = "<select>";\r
-                                               for (var i=0;i<formats.length;i++) {\r
-                                                       selectHtml += "<option value='" + formats[i].mime + "'>" + formats[i].name + "</option>";\r
-                                               }\r
-                                               selectHtml += "</select>";\r
-\r
-                                               var selectCtr = $j("<div></div>", doc)\r
-                                                       .addClass("ui-select-container");\r
-\r
-\r
-                                               var label = $j("<div></div>", doc)\r
-                                                       .addClass("ui-select-label")\r
-                                                       .html("Format:")\r
-                                                       .appendTo(selectCtr);\r
-\r
-                                               var formatSelect = $j(selectHtml, doc).appendTo(selectCtr);\r
-\r
-\r
-                                               selectCtr.appendTo(ctr);\r
-\r
-                                               var buttonCtr = $j("<div></div>", doc).appendTo(ctr);\r
-                                               var saveButton = $j("<button></button>", doc)\r
-                                                       .html("Save file")\r
-                                                       .appendTo(buttonCtr)\r
-\r
-                                               saveButton.click(function() {\r
-                                                       var selectElement = formatSelect.get(0);\r
-                                                       var formatMime = selectElement.options[selectElement.selectedIndex].value;\r
-                                                       var dataString = PE.getDataURI(formatMime);\r
-\r
-                                                       var dialog = $j("<div></div>", doc)\r
-                                                               .attr("id", "save-dialog")\r
-                                                               .attr("title", "Download file")\r
-                                                               .html(\r
-                                                                       "Right click the link below and select \"Save as...\" to save your file.<br/>"\r
-                                                                       + "<br/>"\r
-                                                                       + "<a href=\"" + dataString + "\">Image Link</a>"\r
-                                                               )\r
-                                                               .dialog();\r
-\r
-                                                       // the dialog is added outside the Pixastic container, so get it back in.\r
-                                                       var dialogParent = $j(dialog.get(0).parentNode);\r
-                                                       $j("#pixastic-editor", doc).append(dialogParent);\r
-                                               });\r
-                                       }\r
-                               },\r
-                               /*\r
-                               {\r
-                                       title : "Upload to Flickr",\r
-                                       id : "flickrupload",\r
-                                       content : function($ctr) {\r
-                                               var doc = PE.getDocument();\r
-\r
-                                               function flickrAuthed() {\r
-                                                       var $text = $j("<div />", doc)\r
-                                                               .addClass("action-output-text")\r
-                                                               .html("Authorized as: " + PE.Flickr.getAuthName());\r
-\r
-                                                       var $buttonCtr = $j("<div></div>", doc);\r
-                                                       var $uploadButton = $j("<button></button>", doc)\r
-                                                               .html("Upload image")\r
-                                                               .appendTo($buttonCtr)\r
-\r
-                                                       $uploadButton.click(function() {\r
-                                                               PE.Flickr.uploadImage(PE.getDataURI());\r
-                                                       });\r
-\r
-                                                       $ctr.append($text, $buttonCtr);\r
-                                               }\r
-\r
-                                               var $authCtr = $j("<div />", doc).appendTo($ctr);\r
-\r
-                                               $j("<div />", doc)\r
-                                                       .addClass("action-output-text")\r
-                                                       .html("If you have a Flickr account you can now upload your image to Flickr. You will need to give access to your account first. Click the button below to open an authorization window.")\r
-                                                       .appendTo($authCtr);\r
-\r
-                                               var $buttonCtr = $j("<div></div>", doc).appendTo($authCtr);\r
-                                               var $authButton = $j("<button></button>", doc)\r
-                                                       .html("Authenticate")\r
-                                                       .appendTo($buttonCtr)\r
-\r
-                                               var checkButtonAdded = false;\r
-                                               $authButton.click(function() {\r
-                                                       PE.Flickr.auth();\r
-                                                       if (!checkButtonAdded) {\r
-                                                               checkButtonAdded = true;\r
-\r
-                                                               var $text = $j("<div />", doc)\r
-                                                                       .addClass("action-output-text")\r
-                                                                       .html("Now click the button below when you have authorized access to your Flickr account.");\r
-       \r
-                                                               var $buttonCtr = $j("<div></div>", doc);\r
-       \r
-                                                               $authCtr.append($text, $buttonCtr);\r
-       \r
-                                                               var $checkButton = $j("<button></button>", doc)\r
-                                                                       .html("I have authenticated!")\r
-                                                                       .appendTo($buttonCtr);\r
-       \r
-                                                               $checkButton.click(function() {\r
-                                                                       PE.Flickr.checkAuth(function(res) {\r
-                                                                               if (res.stat == "ok") {\r
-                                                                                       $authCtr.remove();\r
-                                                                                       flickrAuthed();\r
-                                                                               }\r
-                                                                       });\r
-                                                               });\r
-                                                       }\r
-\r
-                                               });\r
-                                       }\r
-                               },\r
-                               */\r
-                               {\r
-                                       title : "Quit",\r
-                                       id : "quit", \r
-                                       content : function(ctr) {\r
-                                               var doc = PE.getDocument();\r
-\r
-                                               $j("<div>Are you sure you want to quit?</div>", doc)\r
-                                                       .addClass("action-output-text")\r
-                                                       .appendTo(ctr);\r
-                                               var $buttonCtr = $j("<div></div>", doc).appendTo(ctr);\r
-\r
-                                               var $quitButton = PE.UI.makeButton("Yes, quit now!")\r
-                                                       .appendTo($buttonCtr)\r
-\r
-                                               $quitButton.click(function() {\r
-                                                       PE.unload();\r
-                                               });\r
-\r
-                                               var $saveButton = PE.UI.makeButton("Save to page and quit")\r
-                                                       .appendTo($buttonCtr)\r
-                                                       .click(function() {\r
-                                                               PE.saveToPage();\r
-                                                               PE.unload();\r
-                                                       });\r
-                                       }\r
-                               }\r
-                       ]\r
-               }\r
-       ]\r
-};\r
-\r
-\r
+(function($) {
+
+var PE = PixasticEditor;
+
+PE.UI.data = {
+       tabs : [
+               {
+                       title : "Reshape",
+                       id : "reshape",
+                       actions : [
+                               {
+                                       title : "Resize",
+                                       id : "resize",
+                                       isAction : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Enter new dimensions below."
+                                               },
+                                               {
+                                                       label : "Width",
+                                                       labelRight : "px",
+                                                       option : "width",
+                                                       type : "number", 
+                                                       range : [1,10000], 
+                                                       step : 1,
+                                                       defaultValue : function() { return PE.getImageWidth(); },
+                                                       ui : "text"
+                                               },
+                                               {
+                                                       label : "Height",
+                                                       labelRight : "px",
+                                                       option : "height",
+                                                       type : "number", 
+                                                       range : [1,10000], 
+                                                       step : 1,
+                                                       defaultValue : function() { return PE.getImageHeight(); },
+                                                       ui : "text"
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Crop",
+                                       id : "crop",
+                                       isAction : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Enter new crop values below or use mouse to select crop area."
+                                               },
+                                               {
+                                                       label : "X",
+                                                       labelRight : "px",
+                                                       option : "left",
+                                                       type : "number", 
+                                                       range : [0,10000], 
+                                                       step : 1,
+                                                       defaultValue : 0,
+                                                       ui : "text"
+                                               },
+                                               {
+                                                       label : "Y",
+                                                       labelRight : "px",
+                                                       option : "top",
+                                                       type : "number", 
+                                                       range : [0,10000], 
+                                                       step : 1,
+                                                       defaultValue : 0,
+                                                       ui : "text"
+                                               },
+                                               {
+                                                       label : "Width",
+                                                       labelRight : "px",
+                                                       option : "width",
+                                                       type : "number", 
+                                                       range : [1,10000], 
+                                                       step : 1,
+                                                       defaultValue : function() { return PE.getImageWidth(); },
+                                                       ui : "text"
+                                               },
+                                               {
+                                                       label : "Height",
+                                                       labelRight : "px",
+                                                       option : "height",
+                                                       type : "number", 
+                                                       range : [1,10000], 
+                                                       step : 1,
+                                                       defaultValue : function() { return PE.getImageHeight(); },
+                                                       ui : "text"
+                                               }
+                                       ],
+                                       onactivate : function() {
+                                               var $canvas = PE.getDisplayCanvas();
+                                               var onchange = function(c) {
+                                                       var doc = PE.getDocument();
+                                                       $j("#input-numeric-crop-left", doc).val(c.x).change();
+                                                       $j("#input-numeric-crop-top", doc).val(c.y).change();
+                                                       $j("#input-numeric-crop-width", doc).val(c.w).change();
+                                                       $j("#input-numeric-crop-height", doc).val(c.h).change();
+                                                       $j("#input-hidden-crop-left", doc).val(c.x).change();
+                                                       $j("#input-hidden-crop-top", doc).val(c.y).change();
+                                                       $j("#input-hidden-crop-width", doc).val(c.w).change();
+                                                       $j("#input-hidden-crop-height", doc).val(c.h).change();
+                                               }
+                                               $canvas.data("Jcrop-onchange", onchange);
+                                               $canvas.Jcrop({onChange:onchange}, PE.getDocument());
+                                       },
+                                       ondeactivate : function() {
+                                               var $canvas = PE.getDisplayCanvas();
+                                               if ($canvas.data("Jcrop") && $canvas.data("Jcrop").destroy)
+                                                       $canvas.data("Jcrop").destroy();
+                                       },
+                                       onafteraction : function(action, isPreview) {
+                                               action.ondeactivate();
+                                               action.onactivate();
+                                               /*
+                                               var $canvas = PE.getDisplayCanvas();
+                                               if ($canvas.data("Jcrop") && $canvas.data("Jcrop").destroy)
+                                                       $canvas.data("Jcrop").destroy();
+                                               var onchange = $canvas.data("Jcrop-onchange");
+                                               $canvas.Jcrop({onChange:onchange});
+                                               */
+                                       }
+                               },
+                               {
+                                       title : "Rotate",
+                                       id : "rotate",
+                                       isAction : true,
+                                       preview : true,
+                                       forcePreview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Enter the angle (-180&deg; to 180&deg;) you want to rotate the picture. Use negative values for clockwise rotation, positive for counterclockwise."
+                                               },
+                                               {
+                                                       label : "Angle",
+                                                       labelRight : "&deg;",
+                                                       option : "angle",
+                                                       type : "number", 
+                                                       range : [-180,180], 
+                                                       step : 1,
+                                                       defaultValue : 0,
+                                                       ui : "text"
+                                               }
+                                       ],
+                                       onactivate : function() {
+                                               var doc = PE.getDocument();
+                                               var $displayCanvas = PE.getDisplayCanvas();
+                                               var dim = Math.min($displayCanvas.attr("height"), 200);
+                                               var $canvas = $j("<canvas></canvas>", doc);
+                                               PE.getOverlay().append($canvas);
+
+                                               $canvas.attr("width", dim);
+                                               $canvas.attr("height", dim);
+                                               $canvas.width(dim);
+                                               $canvas.height(dim);
+
+                                               $canvas.css("marginTop", (($displayCanvas.attr("height") - dim) * 0.5) + "px");
+
+                                               var lineWidth = 20;
+                                               var radius = dim/2 - lineWidth;
+                                               if (radius < 1) radius = 1;
+
+                                               var ctx = $canvas.get(0).getContext("2d");
+                                               ctx.beginPath()
+                                               ctx.arc(dim/2, dim/2, radius, 0, Math.PI*2, true);
+                                               ctx.closePath();
+                                               ctx.fillStyle = "rgba(200,200,200,0.2)";
+                                               ctx.fill();
+                                               ctx.strokeStyle = "rgba(200,200,200,0.5)";
+                                               ctx.lineWidth = 20;
+                                               ctx.stroke();
+
+                                               $j("#image-area", doc).css("cursor", "move");
+
+                                               $overlay = PE.getOverlay();
+
+                                               $canvas.get(0).ondragstart = function() {return false;}
+                                               $canvas.get(0).onselectstart = function() {return false;}
+
+                                               var mx = 0, my = 0;
+                                               var startMouseAngle = 0;
+                                               var startAngle = 0;
+                                               var deltaAngle = 0;
+                                               var angle = 0;
+
+                                               var mouseIsDown = false;
+                                               var onmousedown = function(e) {
+                                                       mouseIsDown = true;
+                                                       var offset = $displayCanvas.offset();
+                                                       mx = (e.pageX - offset.left) - $displayCanvas.attr("width")*0.5;
+                                                       my = (e.pageY - offset.top) - $displayCanvas.attr("height")*0.5;
+                                                       startMouseAngle = Math.atan2(my, mx);
+                                                       startAngle = parseInt($j("#input-numeric-rotate-angle", doc).val(), 10) * Math.PI / 180;
+                                               }
+                                               var onmousemove = function(e) {
+                                                       if (!mouseIsDown) return;
+
+                                                       var offset = $displayCanvas.offset();
+                                                       mx = (e.pageX - offset.left) - $displayCanvas.attr("width")*0.5;
+                                                       my = (e.pageY - offset.top) - $displayCanvas.attr("height")*0.5;
+                                                       deltaAngle = Math.atan2(my, mx) - startMouseAngle;
+                                                       angle = startAngle - deltaAngle;
+                                                       if (angle < -Math.PI) angle += 2*Math.PI;
+                                                       if (angle > Math.PI) angle -= 2*Math.PI;
+                                                       $j("#input-numeric-rotate-angle", doc).val(Math.round(angle * 180 / Math.PI));
+                                                       $j("#input-numeric-rotate-angle", doc).change();
+                                               }
+                                               var onmouseup = function() {
+                                                       mouseIsDown = false;
+                                               }
+
+                                               $j("#image-area", doc).bind("mousedown", onmousedown);
+                                               $j("#image-area", doc).bind("mousemove", onmousemove);
+                                               $j("#image-area", doc).bind("mouseup", onmouseup);
+                                               $canvas.data("onmousedown", onmousedown);
+                                               $canvas.data("onmousemove", onmousemove);
+                                               $canvas.data("onmouseup", onmouseup);
+                                               $displayCanvas.data("rotateCanvas", $canvas);
+                                       },
+                                       ondeactivate : function() {
+                                               var doc = PE.getDocument();
+                                               var $displayCanvas = PE.getDisplayCanvas();
+                                               $overlay = PE.getOverlay();
+                                               $j("#image-area", doc).css("cursor", "default");
+
+                                               var $canvas = $displayCanvas.data("rotateCanvas");
+
+                                               $j("#image-area", doc).unbind("mousedown", $canvas.data("onmousedown"));
+                                               $j("#image-area", doc).unbind("mousemove", $canvas.data("onmousemove"));
+                                               $j("#image-area", doc).unbind("mouseup", $canvas.data("onmouseup"));
+                                               $displayCanvas.removeData("rotateCanvas");
+                                               $canvas.remove();
+                                       },
+                                       onafteraction : function(action, isPreview) {
+                                               if (!isPreview) { // rebuild the rotate widget
+                                                       action.ondeactivate();
+                                                       action.onactivate();
+                                               }
+                                       },
+                                       onoverlayupdate : function() {
+                                               var $canvas = PE.getDisplayCanvas().data("rotateCanvas");
+                                               if ($canvas) {
+                                                       $canvas.css("marginTop", ((PE.getDisplayCanvas().get(0).height - $canvas.get(0).height) * 0.5) + "px");
+                                               }
+                                       }
+                               },
+                               {
+                                       title : "Flip",
+                                       id : "flip",
+                                       isAction : true,
+                                       controls : [
+                                               {
+                                                       label : "Axis",
+                                                       option : "axis",
+                                                       type : "string", 
+                                                       values : [
+                                                               {name:"Horizontal", value:"horizontal"},
+                                                               {name:"Vertical", value:"vertical"}
+                                                       ],
+                                                       defaultValue : "vertical",
+                                                       ui : "select"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               {
+                       title : "Develop",
+                       id : "develop",
+                       actions : [
+                               {
+                                       title : "Brightness & Contrast",
+                                       id : "brightness",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Use the sliders below to adjust the brightness and/or contrast of the image."
+                                               },
+                                               {
+                                                       label : "Brightness",
+                                                       option : "brightness",
+                                                       type : "number", 
+                                                       range : [-100,100], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 1
+                                               },
+                                               {
+                                                       label : "Contrast",
+                                                       option : "contrast",
+                                                       type : "number", 
+                                                       range : [-1,1], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Legacy mode",
+                                                       option : "legacy",
+                                                       type : "boolean", 
+                                                       defaultValue : false,
+                                                       ui : "checkbox"
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Hue/Saturation/Lightness",
+                                       id : "hsl",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Use the sliders below to adjust the hue, saturation and/or lightness of the image."
+                                               },
+                                               {
+                                                       label : "Hue",
+                                                       option : "hue",
+                                                       type : "number", 
+                                                       range : [-180,180], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 1
+                                               },
+                                               {
+                                                       label : "Saturation",
+                                                       option : "saturation",
+                                                       type : "number", 
+                                                       range : [-100,100], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 1
+                                               },
+                                               {
+                                                       label : "Lightness",
+                                                       option : "lightness",
+                                                       type : "number", 
+                                                       range : [-100,100], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 1
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Adjust colors",
+                                       id : "coloradjust",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Use the sliders below to shift the R, G and B channels of the image."
+                                               },
+                                               {
+                                                       label : "Red",
+                                                       option : "red",
+                                                       type : "number", 
+                                                       range : [-1,1], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Green",
+                                                       option : "green",
+                                                       type : "number", 
+                                                       range : [-1,1], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Blue",
+                                                       option : "blue",
+                                                       type : "number", 
+                                                       range : [-1,1], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Desaturate",
+                                       id : "desaturate",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "This will desaturate the image. Select \"Use average\" to use the average value of the R, G and B channels rather than the default mix of 30% red, 59% green and 11% blue."
+                                               },
+                                               {
+                                                       label : "Use average",
+                                                       option : "average",
+                                                       type : "boolean", 
+                                                       defaultValue : false,
+                                                       ui : "checkbox"
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Sepia toning",
+                                       id : "sepia",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Applies a sepia toning effect to the image."
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Invert",
+                                       id : "invert",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "This will invert the colors of the image."
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Lighten",
+                                       id : "lighten",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Use the slider below to lighten or darken the image."
+                                               },
+                                               {
+                                                       label : "Amount",
+                                                       option : "amount",
+                                                       type : "number", 
+                                                       range : [-1,1], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Unsharp mask",
+                                       id : "unsharpmask",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Use the sliders below to adjust the unsharp mask parameters."
+                                               },
+                                               {
+                                                       label : "Amount",
+                                                       option : "amount",
+                                                       type : "number", 
+                                                       range : [0,500], 
+                                                       defaultValue : 200,
+                                                       ui : "slider",
+                                                       step : 2
+                                               },
+                                               {
+                                                       label : "Radius",
+                                                       option : "radius",
+                                                       type : "number", 
+                                                       range : [0,5], 
+                                                       defaultValue : 2,
+                                                       ui : "slider",
+                                                       step : 0.1
+                                               },
+                                               {
+                                                       label : "Threshold",
+                                                       option : "amount",
+                                                       type : "number", 
+                                                       range : [0,255], 
+                                                       defaultValue : 25,
+                                                       ui : "slider",
+                                                       step : 1
+                                               }
+                                       ]
+                               }
+
+                       ]
+               },
+               {
+                       title : "Effects",
+                       id : "effects",
+                       actions : [
+                               {
+                                       title : "Blur",
+                                       id : "blurfast",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Use the slider to set the blur amount."
+                                               },
+                                               {
+                                                       label : "Amount",
+                                                       option : "amount",
+                                                       type : "number", 
+                                                       range : [0,1], 
+                                                       defaultValue : 0.5,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               }
+                                       ]
+
+                               },
+                               {
+                                       title : "Edge detection",
+                                       id : "edges",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Performs edge detection on the image."
+                                               },
+                                               {
+                                                       label : "Greyscale",
+                                                       option : "mono",
+                                                       type : "boolean", 
+                                                       defaultValue : false,
+                                                       ui : "checkbox"
+                                               },
+                                               {
+                                                       label : "Invert",
+                                                       option : "invert",
+                                                       type : "boolean", 
+                                                       defaultValue : false,
+                                                       ui : "checkbox"
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Emboss",
+                                       id : "emboss",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Adds an emboss-like effect to the image. Use the controls below to control the appearance of the effect. Choose \"Blend\" to blend the effect with the original image."
+                                               },
+                                               {
+                                                       label : "Strength",
+                                                       option : "strength",
+                                                       type : "number", 
+                                                       range : [0,10], 
+                                                       defaultValue : 1,
+                                                       ui : "slider",
+                                                       step : 0.1
+                                               },
+                                               {
+                                                       label : "Grey level",
+                                                       option : "greyLevel",
+                                                       type : "number", 
+                                                       range : [0,255], 
+                                                       defaultValue : 180,
+                                                       ui : "slider",
+                                                       step : 1
+                                               },
+                                               {
+                                                       label : "Direction",
+                                                       option : "direction",
+                                                       type : "string", 
+                                                       values : [
+                                                               {name:"Top left", value:"topleft"},
+                                                               {name:"Top", value:"top"},
+                                                               {name:"Top right", value:"topright"},
+                                                               {name:"Right", value:"right"},
+                                                               {name:"Bottom right", value:"bottomright"},
+                                                               {name:"Bottom", value:"bottom"},
+                                                               {name:"Bottom left", value:"bottomleft"},
+                                                               {name:"Left", value:"left"}
+                                                       ],
+                                                       defaultValue : "topleft",
+                                                       ui : "select"
+                                               },
+                                               {
+                                                       label : "Blend",
+                                                       option : "blend",
+                                                       type : "boolean", 
+                                                       defaultValue : false,
+                                                       ui : "checkbox"
+                                               }
+                                       ]
+
+                               },
+                               {
+                                       title : "Glow",
+                                       id : "glow",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Creates a glowing effect on the image."
+                                               },
+                                               {
+                                                       label : "Amount",
+                                                       option : "amount",
+                                                       type : "number", 
+                                                       range : [0,1], 
+                                                       defaultValue : 0.5,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Radius",
+                                                       option : "radius",
+                                                       type : "number", 
+                                                       range : [0,1], 
+                                                       defaultValue : 0.5,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Add noise",
+                                       id : "noise",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Add random noise to the image."
+                                               },
+                                               {
+                                                       label : "Amount",
+                                                       option : "amount",
+                                                       type : "number", 
+                                                       range : [0,1], 
+                                                       defaultValue : 0.5,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Strength",
+                                                       option : "strength",
+                                                       type : "number", 
+                                                       range : [0,1], 
+                                                       defaultValue : 0.5,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Greyscale",
+                                                       option : "mono",
+                                                       type : "boolean", 
+                                                       defaultValue : false,
+                                                       ui : "checkbox"
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Remove noise",
+                                       id : "removenoise",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Attempts to remove noise from the image. Works best for getting rid of single pixels that stand out."
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Pointillize",
+                                       id : "pointillize",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Paints the picture with circular points."
+                                               },
+                                               {
+                                                       label : "Point radius",
+                                                       option : "radius",
+                                                       type : "number", 
+                                                       range : [1,50], 
+                                                       defaultValue : 5,
+                                                       ui : "slider",
+                                                       step : 1
+                                               },
+                                               {
+                                                       label : "Density",
+                                                       option : "density",
+                                                       type : "number", 
+                                                       range : [0,5], 
+                                                       defaultValue : 1,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Noise",
+                                                       option : "noise",
+                                                       type : "number", 
+                                                       range : [0,2], 
+                                                       defaultValue : 1,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Transparent",
+                                                       option : "transparent",
+                                                       type : "boolean", 
+                                                       defaultValue : false,
+                                                       ui : "checkbox"
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Posterize",
+                                       id : "posterize",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Reduces the number of colours to a specified number of levels."
+                                               },
+                                               {
+                                                       label : "Levels",
+                                                       option : "levels",
+                                                       type : "number", 
+                                                       range : [1,32], 
+                                                       defaultValue : 5,
+                                                       ui : "slider",
+                                                       step : 1
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Solarize",
+                                       id : "solarize",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Applies a solarize effect to the image."
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Mosaic",
+                                       id : "mosaic",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Creates a pixelated look."
+                                               },
+                                               {
+                                                       label : "Block size",
+                                                       option : "blockSize",
+                                                       type : "number", 
+                                                       range : [1,100], 
+                                                       defaultValue : 5,
+                                                       ui : "slider",
+                                                       step : 1
+                                               }
+                                       ]
+                               }
+
+
+                       ]
+               },
+               {
+                       title : "Done",
+                       id : "done",
+                       actions : [
+                               {
+                                       title : "Save to page",
+                                       id : "savepage",
+                                       content : function($ctr) {
+                                               var doc = PE.getDocument();
+                                               $j("<div></div>", doc)
+                                                       .addClass("action-output-text")
+                                                       .html("This will save the image to the page.")
+                                                       .appendTo($ctr);
+
+                                               var $buttonCtr = $j("<div></div>", doc).appendTo($ctr);
+                                               var $saveButton = $j("<button></button>", doc)
+                                                       .html("Save image")
+                                                       .appendTo($buttonCtr)
+                                                       .click(function() {
+                                                               PE.saveToPage();
+                                                       });
+
+                                       }
+                               },
+                               {
+                                       title : "Save to file",
+                                       id : "savefile",
+                                       content : function(ctr) {
+                                               var doc = PE.getDocument();
+                                               $j("<div></div>", doc)
+                                                       .addClass("action-output-text")
+                                                       .html("This will save the image to your local computer.")
+                                                       .appendTo(ctr);
+
+                                               var formats = PE.validSaveFormats();
+
+                                               var selectHtml = "<select>";
+                                               for (var i=0;i<formats.length;i++) {
+                                                       selectHtml += "<option value='" + formats[i].mime + "'>" + formats[i].name + "</option>";
+                                               }
+                                               selectHtml += "</select>";
+
+                                               var selectCtr = $j("<div></div>", doc)
+                                                       .addClass("ui-select-container");
+
+
+                                               var label = $j("<div></div>", doc)
+                                                       .addClass("ui-select-label")
+                                                       .html("Format:")
+                                                       .appendTo(selectCtr);
+
+                                               var formatSelect = $j(selectHtml, doc).appendTo(selectCtr);
+
+
+                                               selectCtr.appendTo(ctr);
+
+                                               var buttonCtr = $j("<div></div>", doc).appendTo(ctr);
+                                               var saveButton = $j("<button></button>", doc)
+                                                       .html("Save file")
+                                                       .appendTo(buttonCtr)
+
+                                               saveButton.click(function() {
+                                                       var selectElement = formatSelect.get(0);
+                                                       var formatMime = selectElement.options[selectElement.selectedIndex].value;
+                                                       var dataString = PE.getDataURI(formatMime);
+
+                                                       var dialog = $j("<div></div>", doc)
+                                                               .attr("id", "save-dialog")
+                                                               .attr("title", "Download file")
+                                                               .html(
+                                                                       "Right click the link below and select \"Save as...\" to save your file.<br/>"
+                                                                       + "<br/>"
+                                                                       + "<a href=\"" + dataString + "\">Image Link</a>"
+                                                               )
+                                                               .dialog();
+
+                                                       // the dialog is added outside the Pixastic container, so get it back in.
+                                                       var dialogParent = $j(dialog.get(0).parentNode);
+                                                       $j("#pixastic-editor", doc).append(dialogParent);
+                                               });
+                                       }
+                               },
+                               /*
+                               {
+                                       title : "Upload to Flickr",
+                                       id : "flickrupload",
+                                       content : function($ctr) {
+                                               var doc = PE.getDocument();
+
+                                               function flickrAuthed() {
+                                                       var $text = $j("<div />", doc)
+                                                               .addClass("action-output-text")
+                                                               .html("Authorized as: " + PE.Flickr.getAuthName());
+
+                                                       var $buttonCtr = $j("<div></div>", doc);
+                                                       var $uploadButton = $j("<button></button>", doc)
+                                                               .html("Upload image")
+                                                               .appendTo($buttonCtr)
+
+                                                       $uploadButton.click(function() {
+                                                               PE.Flickr.uploadImage(PE.getDataURI());
+                                                       });
+
+                                                       $ctr.append($text, $buttonCtr);
+                                               }
+
+                                               var $authCtr = $j("<div />", doc).appendTo($ctr);
+
+                                               $j("<div />", doc)
+                                                       .addClass("action-output-text")
+                                                       .html("If you have a Flickr account you can now upload your image to Flickr. You will need to give access to your account first. Click the button below to open an authorization window.")
+                                                       .appendTo($authCtr);
+
+                                               var $buttonCtr = $j("<div></div>", doc).appendTo($authCtr);
+                                               var $authButton = $j("<button></button>", doc)
+                                                       .html("Authenticate")
+                                                       .appendTo($buttonCtr)
+
+                                               var checkButtonAdded = false;
+                                               $authButton.click(function() {
+                                                       PE.Flickr.auth();
+                                                       if (!checkButtonAdded) {
+                                                               checkButtonAdded = true;
+
+                                                               var $text = $j("<div />", doc)
+                                                                       .addClass("action-output-text")
+                                                                       .html("Now click the button below when you have authorized access to your Flickr account.");
+       
+                                                               var $buttonCtr = $j("<div></div>", doc);
+       
+                                                               $authCtr.append($text, $buttonCtr);
+       
+                                                               var $checkButton = $j("<button></button>", doc)
+                                                                       .html("I have authenticated!")
+                                                                       .appendTo($buttonCtr);
+       
+                                                               $checkButton.click(function() {
+                                                                       PE.Flickr.checkAuth(function(res) {
+                                                                               if (res.stat == "ok") {
+                                                                                       $authCtr.remove();
+                                                                                       flickrAuthed();
+                                                                               }
+                                                                       });
+                                                               });
+                                                       }
+
+                                               });
+                                       }
+                               },
+                               */
+                               {
+                                       title : "Quit",
+                                       id : "quit", 
+                                       content : function(ctr) {
+                                               var doc = PE.getDocument();
+
+                                               $j("<div>Are you sure you want to quit?</div>", doc)
+                                                       .addClass("action-output-text")
+                                                       .appendTo(ctr);
+                                               var $buttonCtr = $j("<div></div>", doc).appendTo(ctr);
+
+                                               var $quitButton = PE.UI.makeButton("Yes, quit now!")
+                                                       .appendTo($buttonCtr)
+
+                                               $quitButton.click(function() {
+                                                       PE.unload();
+                                               });
+
+                                               var $saveButton = PE.UI.makeButton("Save to page and quit")
+                                                       .appendTo($buttonCtr)
+                                                       .click(function() {
+                                                               PE.saveToPage();
+                                                               PE.unload();
+                                                       });
+                                       }
+                               }
+                       ]
+               }
+       ]
+};
+
+
 })(PixasticEditor.jQuery);
\ No newline at end of file
index 6edba1a..6789531 100644 (file)
-\r
-var PixasticEditor = (function () {\r
-\r
-       var $frame;     // iframe container element\r
-       var $editor;    // editor container element\r
-\r
-       // various UI structures\r
-       var accordionElements = {};\r
-       var tabElements = {};\r
-       var activeTabId;\r
-       var $activeTabContent;\r
-\r
-       var isRunning = false;\r
-\r
-       var $loadingScreen;\r
-\r
-       var $imageCanvas;       // the canvas holding the current state of the image\r
-       var $displayCanvas;     // the canvas element displayed on the screen, also the working canvas (where preview operations are performed)\r
-       var imageCtx;\r
-\r
-       var imageWidth = 0;     // dimensions of the current image state\r
-       var imageHeight = 0;\r
-\r
-       var undoImages = [];    // canvas elements holding previous image states\r
-       var undoLevels = 10;\r
-\r
-       var doc;\r
-\r
-       var $;\r
-\r
-       // test for valid file formats for toDataURL()\r
-       // we do that by calling it with each of the mime types in testFormats\r
-       // and then doing string checking on the resulting data: URI to see if it succeeded\r
-       var saveFormats = [];\r
-       var testFormats = [["image/jpeg", "JPEG"], ["image/png", "PNG"]];\r
-       var testCanvas = document.createElement("canvas");\r
-       if (testCanvas.toDataURL) {\r
-               testCanvas.width = testCanvas.height = 1;\r
-               for (var i=0;i<testFormats.length;i++) {\r
-                       var data = testCanvas.toDataURL(testFormats[i][0]);\r
-                       if (data.substr(0, 5 + testFormats[i][0].length) == "data:" + testFormats[i][0])\r
-                               saveFormats.push({mime:testFormats[i][0], name:testFormats[i][1]});\r
-               }\r
-       }\r
-\r
-\r
-       // pops up an error dialog with the specified text (errTxt),\r
-       // if no context is provided, the name of the calling function is used.\r
-       // The final message is returned for easy throwing of actual errors\r
-       function errorDialog(errTxt, context) {\r
-               if (!($editor && $editor.get && $editor.get(0)))\r
-                       throw new Error("errorDialog(): $editor doesn't exist");\r
-\r
-               var caller = errorDialog.caller.toString().split(" ")[1];\r
-               caller = caller.substring(0, caller.indexOf("("));\r
-               context = context || caller;\r
-               errTxt = context + "(): " + errTxt;\r
-               var dialog = $j("<div></div>", doc)\r
-                       .addClass("error-dialog")\r
-                       .attr("title", "Oops!")\r
-                       .html(errTxt)\r
-                       .dialog();\r
-               // the dialog is added outside the Pixastic container, so get it back in.\r
-               var dialogParent = $j(dialog.get(0).parentNode);\r
-               dialogParent.appendTo($editor);\r
-\r
-               return errTxt;\r
-       }\r
-       \r
-       function enableTab(id, refresh) {\r
-               if (id == activeTabId && !refresh)\r
-                       return;\r
-\r
-               activeTabId = id;\r
-\r
-               var activeIndex = 0;\r
-\r
-               if ($activeTabContent) {\r
-                       if ($activeTabContent.get(0)) {\r
-                               var $parent = $j($activeTabContent.get(0).parentNode);\r
-                               activeIndex = $parent.data("accordionindex");\r
-                               if ($parent.data("ondeactivate")) {\r
-                                       $parent.data("ondeactivate")();\r
-                               }\r
-                               if ($parent.data("previewCheckbox"))\r
-                                       $parent.data("previewCheckbox").attr("checked", false);\r
-                               $parent.data("uidesc").previewEnabled = false;\r
-                               if ($parent.data("uidesc").forcePreview)\r
-                                       $parent.data("uidesc").previewEnabled = true;\r
-                       }\r
-               }\r
-\r
-\r
-               for (var a in accordionElements) {\r
-                       if (accordionElements.hasOwnProperty(a)) {\r
-                               accordionElements[a].accordion("option", "animated", false);\r
-                               accordionElements[a].accordion("activate", -1);\r
-                               accordionElements[a].hide();\r
-                               tabElements[a].removeClass("active");\r
-\r
-                       }\r
-               }\r
-\r
-               accordionElements[id].accordion("option", "animated", false);\r
-               accordionElements[id].accordion("activate", refresh ? activeIndex : 0);\r
-               tabElements[id].addClass("active");\r
-               accordionElements[id].show();\r
-               accordionElements[id].accordion("option", "animated", "slide");\r
-               resetDisplayCanvas();\r
-       }\r
-\r
-       // revert to a previous image state\r
-       function undo(idx) {\r
-               var undoImage = undoImages[idx];\r
-\r
-               if (!undoImage) \r
-                       throw new Error(errorDialog("Invalid undo state"));\r
-               if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))\r
-                       throw new Error(errorDialog("$imageCanvas doesn't exist"));\r
-\r
-               var canvas = $imageCanvas.get(0);\r
-               addUndo(canvas);\r
-               canvas.width = imageWidth = undoImage.width;\r
-               canvas.height = imageHeight = undoImage.height;\r
-               canvas.getContext("2d").drawImage(undoImage,0,0);\r
-\r
-               enableTab(activeTabId, true);\r
-               resetDisplayCanvas();\r
-       }\r
-\r
-       function addUndo(canvasElement) {\r
-               if (!canvasElement)\r
-                       throw new Error(errorDialog("No undo image state provided"));\r
-\r
-               if (undoImages.length == undoLevels) {\r
-                       undoImages.shift();\r
-               }\r
-               var undoCanvas = document.createElement("canvas");\r
-               undoCanvas.width = canvasElement.width;\r
-               undoCanvas.height = canvasElement.height;\r
-               undoCanvas.getContext("2d").drawImage(canvasElement,0,0);\r
-               $j(undoCanvas).addClass("undo-canvas");\r
-               undoImages.push(undoCanvas);\r
-               updateUndoList();\r
-       }\r
-\r
-       function updateUndoList() {\r
-               var $listCtr = $j("#undo-bar", doc)\r
-                       .html("");\r
-\r
-               var ctrHeight = $listCtr.height();\r
-\r
-               var $testCanvas = $j("<canvas></canvas>", doc)\r
-                       .addClass("undo-canvas-small")\r
-                       .addClass("far-far-away")\r
-                       .appendTo("body");\r
-\r
-               var canvasHeight = $testCanvas.height();\r
-               var canvasWidth = $testCanvas.width();\r
-               var canvasCSSHeight = canvasHeight + parseInt($testCanvas.css("margin-top"),10) + parseInt($testCanvas.css("margin-bottom"),10);\r
-\r
-               $testCanvas.remove();\r
-\r
-               var undoRatio = canvasWidth / canvasHeight;\r
-\r
-               for (var i=undoImages.length-1;i>=0;i--) {\r
-                       (function(){\r
-                               var canvas = document.createElement("canvas");\r
-                               $j(canvas)\r
-                                       .addClass("undo-canvas-small")\r
-                                       .attr("width", canvasWidth)\r
-                                       .attr("height", canvasHeight);\r
-\r
-                               var image = undoImages[i];\r
-                               $j(image).show();\r
-                               \r
-                               var undoWidth, undoHeight;\r
-                               var imageRatio = image.width / image.height;\r
-\r
-                               if (imageRatio > undoRatio) {   // image too wide\r
-                                       undoWidth = canvasWidth;\r
-                                       undoHeight = canvasWidth / imageRatio;\r
-                               } else {\r
-                                       undoWidth = canvasHeight * imageRatio;\r
-                                       undoHeight = canvasHeight;\r
-                               }\r
-\r
-                               var restWidth = canvasWidth - undoWidth;\r
-                               var restHeight = canvasHeight - undoHeight;\r
-\r
-                               canvas.getContext("2d").drawImage(\r
-                                       image,\r
-                                       0,0,image.width,image.height,\r
-                                       restWidth*0.5, restHeight*0.5,\r
-                                       undoWidth, undoHeight\r
-                               );\r
-\r
-\r
-                               $link = $j("<a href='#'></a>", doc)\r
-                                       .addClass("undo-link")\r
-                                       .appendTo($listCtr)\r
-                                       .mouseover(function(){ $j(this).addClass("hover") })\r
-                                       .mouseout(function(){ $j(this).removeClass("hover") });\r
-                               $j(canvas).appendTo($link);\r
-\r
-                               var displayShowing;\r
-                               var undoIndex = i;\r
-                               $link.click(function() {\r
-                                       $j(image).hide();\r
-                                       $j(image).remove();\r
-                                       undo(undoIndex);\r
-                                       if (displayShowing)\r
-                                               $displayCanvas.show();\r
-                                       $j(".jcrop-holder", doc).show();\r
-                               });\r
-\r
-                               $link.mouseover(function() {\r
-                                       displayShowing = $displayCanvas.css("display") != "none";\r
-                                       var $imagectr = $j("#image-container", doc);\r
-\r
-                                       $j(".jcrop-holder", doc).hide();\r
-                                       $displayCanvas.hide();\r
-                                       $j(image).appendTo($imagectr);\r
-\r
-                                       var h1 = $j("#image-area", doc).height();\r
-                                       var h2 = image.height;\r
-                                       var m = Math.max(0, (h1 - h2) / 2);\r
-                                       $imagectr.css("marginTop", m);\r
-                       \r
-                                       $imagectr.height(image.height);\r
-                               });\r
-\r
-                               $link.mouseout(function() {\r
-                                       $j(image).remove();\r
-                                       if (displayShowing)\r
-                                               $displayCanvas.show();\r
-                                       $j(".jcrop-holder", doc).show();\r
-                                       updateDisplayCanvas();\r
-                               });\r
-\r
-\r
-                               $j(canvas).attr("title", "Click to revert to this previous image");\r
-\r
-                       })();\r
-               }\r
-       }\r
-\r
-\r
-       function applyAction(id, options, afteraction) {\r
-               if (!Pixastic.Actions[id])\r
-                       throw new Error("applyAction(): unknown action [" + id + "]");\r
-\r
-               $j("#action-bar-overlay", doc).show();\r
-\r
-               setTimeout(function() {\r
-                       options.leaveDOM = true;\r
-                       var canvasElement = $imageCanvas.get(0);\r
-                       addUndo(canvasElement)\r
-       \r
-                       var res = Pixastic.process(\r
-                               canvasElement, id, options,\r
-                               function(resCanvas) {\r
-                                       canvasElement.width = imageWidth = resCanvas.width;\r
-                                       canvasElement.height = imageHeight = resCanvas.height;\r
-       \r
-                                       var ctx = canvasElement.getContext("2d");\r
-                                       ctx.clearRect(0,0,imageWidth,imageHeight);\r
-                                       ctx.drawImage(resCanvas,0,0);\r
-                                       $imageCanvas = $j(canvasElement);\r
-                                       resetDisplayCanvas();\r
-       \r
-                                       $j("#action-bar-overlay", doc).hide();\r
-\r
-                                       if (afteraction)\r
-                                               afteraction();\r
-                               }\r
-                       );\r
-                       if (!res)\r
-                               throw new Error("applyAction(): Pixastic.process() failed for action [" + id + "]");\r
-               },1);\r
-       }\r
-\r
-\r
-       function previewAction(id, options, afteraction) {\r
-               if (!Pixastic.Actions[id])\r
-                       throw new Error("applyAction(): unknown action [" + id + "]");\r
-\r
-               $j("#action-bar-overlay", doc).show();\r
-\r
-               resetDisplayCanvas();\r
-\r
-               options.leaveDOM = true;\r
-               var canvasElement = $displayCanvas.get(0);\r
-\r
-               var res = Pixastic.process(\r
-                       canvasElement, id, options,\r
-                       function(resCanvas) {\r
-\r
-                               canvasElement.width = resCanvas.width;\r
-                               canvasElement.height = resCanvas.height;\r
-\r
-                               var ctx = canvasElement.getContext("2d");\r
-                               ctx.clearRect(0,0,canvasElement.width,canvasElement.height);\r
-                               ctx.drawImage(resCanvas,0,0);\r
-                               updateDisplayCanvas();\r
-                               updateOverlay();\r
-\r
-                               $j("#action-bar-overlay", doc).hide();\r
-\r
-                               if (afteraction)\r
-                                       afteraction();\r
-                       }\r
-               );\r
-       }\r
-\r
-       var onwindowresize = function() {\r
-               updateDisplayCanvas();\r
-               updateOverlay();\r
-       }\r
-\r
-       var baseUrl = ""\r
-\r
-       function buildEditor() {\r
-               var styles = [\r
-                       "jquery-ui-1.7.1.custom.css",\r
-                       "jquery.Jcrop.css",\r
-                       "pixastic.css"\r
-               ];\r
-\r
-               for (var i=0;i<styles.length;i++) {\r
-                       var s = doc.createElement("link");\r
-                       s.href = baseUrl + styles[i];\r
-                       s.type = "text/css";\r
-                       s.rel = "stylesheet";\r
-                       doc.getElementsByTagName("head")[0].appendChild( s );\r
-               }\r
-\r
-               undoImages = [];\r
-               accordionElements = {};\r
-               tabElements = {};\r
-               activeTabId = -1;\r
-               $activeTabContent = null;\r
-\r
-               // setup DOM UI skeleton\r
-               $editor = $j("<div />", doc)\r
-                       .attr("id", "pixastic-editor")\r
-                       .appendTo($j(doc.body));\r
-\r
-               $editor.append(\r
-                       $j("<div id='background' />", doc),\r
-                       $j("<div id='edit-ctr-1' />", doc).append(\r
-                               $j("<div id='edit-ctr-2' />", doc).append(\r
-                                       $j("<div id='controls-bar' />", doc).append(\r
-                                               $j("<div id='action-bar' />", doc).append(\r
-                                                       $j("<div id='action-bar-overlay' />", doc)\r
-                                               ),\r
-                                               $j("<div id='undo-bar' />", doc)\r
-                                       ),\r
-                                       $j("<div id='image-area' />", doc).append(\r
-                                               $j("<div id='image-area-sub' />", doc).append(\r
-                                                       $j("<div id='image-container' />", doc),\r
-                                                       $j("<div id='image-overlay-container' />", doc).append(\r
-                                                               $j("<div id='image-overlay' />", doc)\r
-                                                       )\r
-                                               )\r
-                                       )\r
-                               )\r
-                       ),\r
-                       $j("<div id='main-bar' />", doc),\r
-                       $j("<div id='powered-by-pixastic'><a href=\"http://www.pixastic.com/\" target=\"_blank\">Powered by Pixastic</a></div>", doc)\r
-               );\r
-\r
-               $j("#image-container", doc).append(\r
-                       $displayCanvas = $j("<canvas />", doc)\r
-                               .addClass("display-canvas")\r
-               );\r
-\r
-               // loop through all  defined UI action controls\r
-               var tabs = PixasticEditor.UI.data.tabs;\r
-\r
-               for (var i=0;i<tabs.length;i++) {\r
-                       (function() {\r
-       \r
-                       var tab = tabs[i];\r
-\r
-                       var $tabElement = $j("<a href=\"#\">" + tab.title + "</a>", doc)\r
-                               .attr("id", "main-tab-button-" + tab.id)\r
-                               .addClass("main-tab")\r
-                               .click(function() {\r
-                                       enableTab(tab.id);\r
-                               })\r
-                               .mouseover(function(){ $j(this).addClass("hover") })\r
-                               .mouseout(function(){ $j(this).removeClass("hover") });\r
-       \r
-                       $j("#main-bar", doc).append($tabElement);\r
-\r
-                       tabElements[tab.id] = $tabElement;\r
-\r
-                       var $menu = $j("<div/>", doc);\r
-                       accordionElements[tab.id] = $menu;\r
-\r
-                       for (var j=0;j<tab.actions.length;j++) {\r
-                               (function() {\r
-\r
-                               var action = tab.actions[j];\r
-\r
-                               var $actionElement = $j("<div><h3><a href=\"#\">" + action.title + "</a></h3></div>", doc)\r
-\r
-                               $menu.append($actionElement);\r
-\r
-                               var $content = $j("<div></div>", doc)\r
-                                       .attr("id", "pixastic-action-tab-content-" + action.id)\r
-                                       .appendTo($actionElement);\r
-\r
-                               var controlOptions = [];\r
-\r
-                               action.previewEnabled = false;\r
-                               if (action.forcePreview)\r
-                                       action.previewEnabled = true;\r
-\r
-                               function togglePreview(enable, doAction) {\r
-                                       if (enable && !action.previewEnabled && doAction)\r
-                                               doAction(true);\r
-                                       if (!enable && action.previewEnabled)\r
-                                               resetDisplayCanvas();\r
-                       \r
-                                       action.previewEnabled = enable;\r
-                               }\r
-\r
-                               var reset = function() {\r
-                                       for (var i in controlOptions) {\r
-                                               if (controlOptions.hasOwnProperty(i)) {\r
-                                                       controlOptions[i].reset();\r
-                                               }\r
-                                       }\r
-                                       if (action.previewEnabled)\r
-                                               doAction(true);\r
-                               }\r
-                               var doAction = function(isPreview) {\r
-                                       var options = {};\r
-                                       for (var i in controlOptions) {\r
-                                               if (controlOptions.hasOwnProperty(i)) {\r
-                                                       options[i] = controlOptions[i].valueField.val();\r
-                                               }\r
-                                       }\r
-\r
-                                       var afteraction = function() {\r
-                                               if (action.onafteraction)\r
-                                                       action.onafteraction(action, isPreview);\r
-                                               if (!isPreview)\r
-                                                       resetDisplayCanvas();\r
-       \r
-                                               if (!isPreview && !action.forcePreview) {\r
-                                                       $j("#pixastic-input-preview-" + action.id, doc).attr("checked", false);\r
-                                                       togglePreview(false);\r
-                                                       reset();\r
-                                               }\r
-                                       }\r
-\r
-                                       if (isPreview) {\r
-                                               previewAction(action.id, options, afteraction);\r
-                                       } else {\r
-                                               applyAction(action.id, options, afteraction);\r
-                                       }\r
-\r
-                               }\r
-\r
-                               var hadInputs = false;\r
-\r
-                               if (action.controls) {\r
-                                       var onChange = function() {};\r
-                                       if (action.isAction && action.preview) {\r
-                                               onChange = function() {\r
-                                                       if (action.previewEnabled)\r
-                                                               doAction(true)\r
-                                               };\r
-                                       }\r
-\r
-                                       for (var k=0;k<action.controls.length;k++) {\r
-                                               var control = action.controls[k];\r
-                                               if (typeof control.defaultValue != "function") {\r
-                                                       (function(){\r
-                                                       var defVal = control.defaultValue;\r
-                                                       control.defaultValue = function() {\r
-                                                               return defVal;\r
-                                                       }\r
-                                                       })();\r
-                                               }\r
-                                               var controlId = action.id + "-" + control.option;\r
-\r
-                                               if (control.type != "output")\r
-                                                       hadInputs = true;\r
-\r
-                                               switch (control.type) {\r
-                                                       case "number" :\r
-                                                               switch (control.ui) {\r
-                                                                       case "slider" : \r
-                                                                               var slider = PixasticEditor.UI.makeSlider(\r
-                                                                                       control.label, controlId, \r
-                                                                                       control.range[0], control.range[1], control.step, control.defaultValue, onChange\r
-                                                                               );\r
-               \r
-                                                                               slider.container.appendTo($content);\r
-                                                                               controlOptions[control.option] = slider;\r
-                                                                               break;\r
-                                                                       case "text" : \r
-                                                                               var text = PixasticEditor.UI.makeNumericInput(\r
-                                                                                       control.label, control.labelRight, controlId, \r
-                                                                                       control.range[0], control.range[1], control.step, control.defaultValue, onChange\r
-                                                                               );\r
-                                                                               text.container.appendTo($content);\r
-                                                                               controlOptions[control.option] = text;\r
-                                                                               break;\r
-                                                               }\r
-                                                               break;\r
-                                                       case "boolean" :\r
-                                                               switch (control.ui) {\r
-                                                                       case "checkbox" : \r
-                                                                               var checkbox = PixasticEditor.UI.makeCheckbox(\r
-                                                                                       control.label, controlId, control.defaultValue, onChange\r
-                                                                               );\r
-               \r
-                                                                               checkbox.container.appendTo($content);\r
-                                                                               controlOptions[control.option] = checkbox;\r
-                                                                               break;\r
-                                                               }\r
-                                                       case "string" :\r
-                                                               switch (control.ui) {\r
-                                                                       case "select" : \r
-                                                                               var select = PixasticEditor.UI.makeSelect(\r
-                                                                                       control.label, controlId, control.values, control.defaultValue, onChange\r
-                                                                               );\r
-               \r
-                                                                               select.container.appendTo($content);\r
-                                                                               controlOptions[control.option] = select;\r
-                                                                               break;\r
-                                                               }\r
-                                                               break;\r
-                                                       case "output" :\r
-                                                               var outputText = $j("<div></div>", doc)\r
-                                                                       .addClass("ui-action-output")\r
-                                                                       .html(control.content)\r
-                                                                       .appendTo($content);\r
-                                                               break;\r
-                                               }\r
-                                       }\r
-                               }\r
-\r
-                               if (action.isAction) {\r
-\r
-                                       var $applyButton = PixasticEditor.UI.makeButton("Apply")\r
-                                               .addClass("pixastic-option-button-apply")\r
-                                               .click(function() {doAction();});\r
-\r
-                                       $content.append($applyButton);\r
-\r
-                                       if (hadInputs) {\r
-                                               var $resetButton = PixasticEditor.UI.makeButton("Reset")\r
-                                                       .addClass("pixastic-option-button-reset")\r
-                                                       .click(reset);\r
-       \r
-                                               $content.append($resetButton)\r
-                                       }\r
-\r
-                                       if (action.preview && !action.forcePreview) {\r
-                                               var $checkctr = $j("<div></div>", doc)\r
-                                                       .addClass("ui-checkbox-container")\r
-                                                       .addClass("ui-preview-checkbox-container");\r
-\r
-                                               var $label = $j("<label></label>", doc)\r
-                                                       .addClass("ui-checkbox-label")\r
-                                                       .attr("for", "pixastic-input-preview-" + action.id)\r
-                                                       .html("Preview:")\r
-                                                       .appendTo($checkctr);\r
-\r
-                                               var $checkbox = $j("<input type=\"checkbox\"></input>", doc)\r
-                                                       .addClass("ui-checkbox")\r
-                                                       .attr("id", "pixastic-input-preview-" + action.id)\r
-                                                       .appendTo($checkctr)\r
-                                                       .change(function() {\r
-                                                               togglePreview(this.checked, doAction)\r
-                                                       });\r
-\r
-                                               $content.append($checkctr);\r
-\r
-                                               $content.data("previewCheckbox", $checkbox);\r
-                                       }\r
-\r
-                               }\r
-\r
-\r
-                               if (typeof action.content == "function") {\r
-                                       action.content($content);\r
-                               }\r
-\r
-                               // stupid hack to make it possible to get $content in change event (below)\r
-                               $j("<span></span>", doc).appendTo($content);\r
-\r
-                               $content.data("controlOptions", controlOptions);\r
-                               $content.data("onactivate", action.onactivate);\r
-                               $content.data("ondeactivate", action.ondeactivate);\r
-                               $content.data("onoverlayupdate", action.onoverlayupdate);\r
-                               $content.data("accordionindex", j);\r
-                               $content.data("uidesc", action);\r
-\r
-                               })();\r
-                       }\r
-       \r
-                       $j("#action-bar", doc).append($menu);\r
-\r
-                       $menu.hide().accordion({\r
-                               header: "h3",\r
-                               autoHeight : false,\r
-                               collapsible : true,\r
-                               active: -1\r
-                       })\r
-                       .bind("accordionchange", \r
-                               function(event, ui) {\r
-                                       resetDisplayCanvas();\r
-\r
-                                       // oldContent / newContent are arrays of whatever elements are present in the content area\r
-                                       // We need the parent element (the one holding the content) but if there is no content, how do we get it?\r
-                                       // fixed above by always appending a <span> but that's ugly and needs to be done in some other way\r
-                                       if (ui.oldContent.get(0)) {\r
-                                               var $parent = $j(ui.oldContent.get(0).parentNode);\r
-                                               if ($parent.data("ondeactivate")) {\r
-                                                       $parent.data("ondeactivate")();\r
-                                               }\r
-                                       }\r
-                                       $activeTabContent = ui.newContent;\r
-\r
-                                       if (ui.newContent.get(0)) {\r
-                                               var $parent = $j(ui.newContent.get(0).parentNode);\r
-                                               if ($parent.data("previewCheckbox"))\r
-                                                       $parent.data("previewCheckbox").attr("checked", false);\r
-                                               $parent.data("uidesc").previewEnabled = false;\r
-                                               if ($parent.data("uidesc").forcePreview)\r
-                                                       $parent.data("uidesc").previewEnabled = true;\r
-\r
-                                               var controlOptions = $parent.data("controlOptions");\r
-                                               for (var i in controlOptions) {\r
-                                                       if (controlOptions.hasOwnProperty(i)) {\r
-                                                               controlOptions[i].reset();\r
-                                                       }\r
-                                               }\r
-                                               if ($parent.data("onactivate")) {\r
-                                                       $parent.data("onactivate")();\r
-                                               }\r
-                                       }\r
-                                       updateDisplayCanvas();\r
-\r
-                               }\r
-                       );\r
-\r
-       \r
-                       })();\r
-               }\r
-\r
-               $j(window).bind("resize", onwindowresize);\r
-       }\r
-\r
-       function showLoadingScreen() {\r
-               if ($loadingScreen) {\r
-                       $loadingScreen.show();\r
-                       return;\r
-               }\r
-               $loadingScreen = $j("<div id=\"loading-screen\" />")\r
-               var $ctr = $j("<div id=\"loading-screen-cell\" />");\r
-               $j("<div />")\r
-                       .addClass("spinner")\r
-                       .appendTo($ctr);\r
-               $loadingScreen.append($ctr);\r
-               $loadingScreen.appendTo("body");\r
-       }\r
-\r
-       function hideLoadingScreen() {\r
-               setTimeout(function() {\r
-                       $loadingScreen.hide();\r
-               }, 1);\r
-       }\r
-\r
-       var oldScrollLeft;\r
-       var oldScrollTop;\r
-       var oldOverflow;\r
-\r
-       // fire it up\r
-       function init(callback) {\r
-               isRunning = true;\r
-\r
-               showLoadingScreen();\r
-\r
-               oldScrollLeft = document.body.scrollLeft;\r
-               oldScrollTop = document.body.scrollTop;\r
-               oldOverflow = document.body.style.overflow;\r
-\r
-               document.body.scrollLeft = 0;\r
-               document.body.scrollTop = 0;\r
-               document.body.style.overflow = "hidden";\r
-\r
-               $frame = $j("<iframe />");\r
-               $frame.hide();\r
-               $frame.css({\r
-                       position : "absolute",\r
-                       left : document.body.scrollLeft + "px",\r
-                       top : document.body.scrollTop + "px",\r
-                       width : "100%",\r
-                       height : "100%",\r
-                       zIndex : "11"\r
-               });\r
-               $frame.load(function(){\r
-                       doc = $frame.get(0).contentDocument;\r
-\r
-                       buildEditor();\r
-                       callback();\r
-                       $frame.show();\r
-                       hideLoadingScreen();\r
-                       setTimeout(function(){\r
-                               updateDisplayCanvas();\r
-                       },10);\r
-               });\r
-               $frame.appendTo("body");\r
-       }\r
-\r
-       // unload the editor, remove all elements added to the page and restore whatever properties we messed with\r
-       function unload() {\r
-               $j(window).unbind("resize", onwindowresize);\r
-               $frame.hide();\r
-               $editor.hide();\r
-               $editor.remove();\r
-               $frame.remove();\r
-\r
-               document.body.scrollLeft = oldScrollLeft;\r
-               document.body.scrollTop = oldScrollTop;\r
-               document.body.style.overflow = oldOverflow;\r
-\r
-               isRunning = false;\r
-       }\r
-\r
-\r
-       // resets the display canvas (clears the canvas and repaints the current state)\r
-       // then updates display and overlay\r
-       function resetDisplayCanvas() {\r
-               if (!($displayCanvas && $displayCanvas.get))    throw new Error(errorDialog("$displayCanvas doesn't exist"));\r
-               if (!($imageCanvas && $imageCanvas.get))        throw new Error(errorDialog("$imageCanvas doesn't exist"));\r
-\r
-               var display = $displayCanvas.get(0);\r
-               var image = $imageCanvas.get(0);\r
-\r
-               if (!display)   throw new Error(errorDialog("resetDisplayCanvas(): No elements in $displayCanvas"));\r
-               if (!image)     throw new Error(errorDialog("resetDisplayCanvas(): No elements in $imageCanvas"));\r
-\r
-               display.width = imageWidth;\r
-               display.height = imageHeight;\r
-               display.getContext("2d").drawImage( image, 0, 0 );\r
-\r
-               updateDisplayCanvas();\r
-               updateOverlay();\r
-       }\r
-\r
-       // updates the display by resetting the height and margin of the image container\r
-       // this is mainly to keep vertical centering\r
-       function updateDisplayCanvas() {\r
-               var $imageCtr = $j("#image-container", doc);\r
-               var $editArea = $j("#image-area", doc);\r
-\r
-               if (!$imageCtr.get(0))          throw new Error(errorDialog("updateDisplayCanvas(): $imageCtr doesn't exist"));\r
-               if (!$displayCanvas.get(0))     throw new Error(errorDialog("updateDisplayCanvas(): $displayCanvas doesn't exist"));\r
-               if (!$editArea.get(0))          throw new Error(errorDialog("updateDisplayCanvas(): $editArea doesn't exist"));\r
-\r
-               var h2 = $displayCanvas.get(0).height;\r
-               var h1 = $j("#image-area", doc).height();\r
-               var m = Math.max(0, (h1 - h2) / 2);\r
-               $imageCtr.height(h2);\r
-               $imageCtr.css("marginTop", m);\r
-       }\r
-\r
-       // basically the same as updateDisplayCanvas but for the image overlay\r
-       function updateOverlay() {\r
-               var $overlay = $j("#image-overlay-container", doc);\r
-               var $imagectr = $j("#image-container", doc);\r
-               $overlay.height($imagectr.height());\r
-               $overlay.css("marginTop", $imagectr.css("marginTop"));\r
-\r
-               if ($activeTabContent && $activeTabContent.get(0)) {\r
-                       var $tabContent = $j($activeTabContent.get(0).parentNode);\r
-                       if (typeof $tabContent.data("onoverlayupdate") == "function")\r
-                               $tabContent.data("onoverlayupdate")();\r
-               }\r
-       }\r
-\r
-       var imageIsLoading = false;\r
-       var originalImageElement;\r
-       var $tmpImg;\r
-\r
-       function loadImage(imgEl) {\r
-               if (imageIsLoading) \r
-                       return;\r
-\r
-               imageIsLoading = true;\r
-\r
-               originalImageElement = imgEl;\r
-\r
-               $imageCanvas = $j("<canvas />", doc);\r
-               imageCtx = $imageCanvas.get(0).getContext("2d");\r
-\r
-               imageWidth = 0;\r
-               imageHeight = 0;\r
-               $imageCanvas.attr("width", 0);\r
-               $imageCanvas.attr("height", 0);\r
-\r
-               if (imgEl.tagName.toLowerCase() == "img" && !imgEl._pixasticCanvas) {\r
-                       var onload = function(el) {\r
-                               imageWidth = el.offsetWidth;\r
-                               imageHeight = el.offsetHeight;\r
-                               $imageCanvas.attr("width", imageWidth);\r
-                               $imageCanvas.attr("height", imageHeight);\r
-                               imageCtx.drawImage(el,0,0);\r
-                               $tmpImg.remove();\r
-                               imageIsLoading = false;\r
-                               enableTab("reshape");\r
-                               setTimeout(function() {\r
-                                       resetDisplayCanvas();\r
-                               }, 10);\r
-                       }\r
-                       $tmpImg = $j("<img />", doc)\r
-                               .css("position", "absolute")\r
-                               .css("left", "-9999px")\r
-                               .css("top", "-9999px")\r
-                               .appendTo("body")\r
-                               .load(function(){onload(this);})\r
-                               .error(function(){\r
-                                       throw new Error("Could not load temporary copy image. Is provided image valid?");\r
-                                       unload();\r
-                               })\r
-                               .attr("src", imgEl.src);\r
-                               if ($tmpImg.attr("complete")) {\r
-                                       onload($tmpImg.get(0));\r
-                               }\r
-               } else {\r
-                       var $canvas = imgEl._pixasticCanvas || imgEl;\r
-                       imageWidth = $canvas.attr("width");\r
-                       imageHeight = $canvas.attr("height");\r
-                       $imageCanvas.attr("width", imageWidth);\r
-                       $imageCanvas.attr("height", imageHeight);\r
-                       imageCtx.drawImage($canvas.get(0), 0, 0);\r
-                       imageIsLoading = false;\r
-                       enableTab("reshape");\r
-                       resetDisplayCanvas();\r
-               }\r
-       }\r
-\r
-       // return public interface\r
-       return {\r
-               /*\r
-               // don't call. For now we must load the image immediately via load()\r
-               loadImage : function(imgEl) {\r
-                       if (!isRunning) return false;\r
-                       loadImage(imgEl);\r
-               },\r
-               */\r
-               saveToPage : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::saveToPage(): Editor is not running");\r
-\r
-                       var $canvas = PixasticEditor.getImageCanvas();\r
-                       var img = PixasticEditor.getOriginalImage();\r
-                       if (img.tagName.toLowerCase() == "canvas") {\r
-                               img.width = $canvas.attr("width");\r
-                               img.height = $canvas.attr("height");\r
-                               img.getContext("2d").drawImage($canvas.get(0), 0, 0);\r
-                       } else {\r
-                               img.src = PixasticEditor.getDataURI();\r
-                       }\r
-                       img._pixasticCanvas = PixasticEditor.getImageCanvas();\r
-               },\r
-               load : function(img, customBaseUrl) {\r
-                       if (isRunning) return false;\r
-\r
-                       if (!img)\r
-                               throw new Error("Must be called with an image or canvas as its first argument", "PixasticEditor::load")\r
-\r
-                       $ = PixasticEditor.jQuery;\r
-\r
-                       baseUrl = customBaseUrl || "http://www.pixastic.com/editor-test/";\r
-\r
-                       init(function() {\r
-                               if (img && img.tagName.toLowerCase() == "img" || img.tagName.toLowerCase() == "canvas") {\r
-                                       loadImage(img);\r
-                               }\r
-                       });\r
-               },\r
-\r
-               unload : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::unload(): Editor is not running");\r
-                       unload();\r
-               },\r
-\r
-               getDocument : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getDocument(): Editor is not running");\r
-\r
-                       return doc;\r
-               },\r
-\r
-               validSaveFormats : function() {\r
-                       return saveFormats;\r
-               },\r
-\r
-               getOriginalImage : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getOriginalImage(): Editor is not running");\r
-                       return originalImageElement;\r
-               },\r
-\r
-               getDataURI : function(mime) {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getDataURI(): Editor is not running");\r
-\r
-                       if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))\r
-                               throw new Error(errorDialog("$imageCanvas doesn't exist", "getImageCanvas"));\r
-\r
-                       return $imageCanvas.get(0).toDataURL(mime||"image/png");\r
-               },\r
-\r
-               getImageCanvas : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getImageCanvas(): Editor is not running");\r
-\r
-                       if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))\r
-                               throw new Error(errorDialog("$imageCanvas doesn't exist", "getImageCanvas"));\r
-\r
-                       return $imageCanvas;\r
-               },\r
-               getOverlay : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getOverlay(): Editor is not running");\r
-\r
-                       return $j("#image-overlay", doc);\r
-               },\r
-               getDisplayCanvas : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getDisplayCanvas(): Editor is not running");\r
-\r
-                       if (!($displayCanvas && $displayCanvas.get && $displayCanvas.get(0)))\r
-                               throw new Error(errorDialog("$displayCanvas doesn't exist", "getDisplayCanvas"));\r
-                       return $displayCanvas;\r
-               },\r
-               getDisplayWidth : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getDisplayWidth(): Editor is not running");\r
-\r
-                       return displayWidth;\r
-               },\r
-               getDisplayHeight : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getDisplayHeight(): Editor is not running");\r
-\r
-                       return displayHeight;\r
-               },\r
-               getImageWidth : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getImageWidth(): Editor is not running");\r
-\r
-                       return imageWidth;\r
-               },\r
-               getImageHeight : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::getImageHeight(): Editor is not running");\r
-\r
-                       return imageHeight;\r
-               },\r
-               errorDialog : function() {\r
-                       if (!isRunning) throw new Error("PixasticEditor::errorDialog(): Editor is not running");\r
-\r
-                       return errorDialog.apply(null, arguments);\r
-               }\r
-       }\r
-\r
+
+var PixasticEditor = (function () {
+
+       var $frame;     // iframe container element
+       var $editor;    // editor container element
+
+       // various UI structures
+       var accordionElements = {};
+       var tabElements = {};
+       var activeTabId;
+       var $activeTabContent;
+
+       var isRunning = false;
+
+       var $loadingScreen;
+
+       var $imageCanvas;       // the canvas holding the current state of the image
+       var $displayCanvas;     // the canvas element displayed on the screen, also the working canvas (where preview operations are performed)
+       var imageCtx;
+
+       var imageWidth = 0;     // dimensions of the current image state
+       var imageHeight = 0;
+
+       var undoImages = [];    // canvas elements holding previous image states
+       var undoLevels = 10;
+
+       var doc;
+
+       var $;
+
+       // test for valid file formats for toDataURL()
+       // we do that by calling it with each of the mime types in testFormats
+       // and then doing string checking on the resulting data: URI to see if it succeeded
+       var saveFormats = [];
+       var testFormats = [["image/jpeg", "JPEG"], ["image/png", "PNG"]];
+       var testCanvas = document.createElement("canvas");
+       if (testCanvas.toDataURL) {
+               testCanvas.width = testCanvas.height = 1;
+               for (var i=0;i<testFormats.length;i++) {
+                       var data = testCanvas.toDataURL(testFormats[i][0]);
+                       if (data.substr(0, 5 + testFormats[i][0].length) == "data:" + testFormats[i][0])
+                               saveFormats.push({mime:testFormats[i][0], name:testFormats[i][1]});
+               }
+       }
+
+
+       // pops up an error dialog with the specified text (errTxt),
+       // if no context is provided, the name of the calling function is used.
+       // The final message is returned for easy throwing of actual errors
+       function errorDialog(errTxt, context) {
+               if (!($editor && $editor.get && $editor.get(0)))
+                       throw new Error("errorDialog(): $editor doesn't exist");
+
+               var caller = errorDialog.caller.toString().split(" ")[1];
+               caller = caller.substring(0, caller.indexOf("("));
+               context = context || caller;
+               errTxt = context + "(): " + errTxt;
+               var dialog = $j("<div></div>", doc)
+                       .addClass("error-dialog")
+                       .attr("title", "Oops!")
+                       .html(errTxt)
+                       .dialog();
+               // the dialog is added outside the Pixastic container, so get it back in.
+               var dialogParent = $j(dialog.get(0).parentNode);
+               dialogParent.appendTo($editor);
+
+               return errTxt;
+       }
+       
+       function enableTab(id, refresh) {
+               if (id == activeTabId && !refresh)
+                       return;
+
+               activeTabId = id;
+
+               var activeIndex = 0;
+
+               if ($activeTabContent) {
+                       if ($activeTabContent.get(0)) {
+                               var $parent = $j($activeTabContent.get(0).parentNode);
+                               activeIndex = $parent.data("accordionindex");
+                               if ($parent.data("ondeactivate")) {
+                                       $parent.data("ondeactivate")();
+                               }
+                               if ($parent.data("previewCheckbox"))
+                                       $parent.data("previewCheckbox").attr("checked", false);
+                               $parent.data("uidesc").previewEnabled = false;
+                               if ($parent.data("uidesc").forcePreview)
+                                       $parent.data("uidesc").previewEnabled = true;
+                       }
+               }
+
+
+               for (var a in accordionElements) {
+                       if (accordionElements.hasOwnProperty(a)) {
+                               accordionElements[a].accordion("option", "animated", false);
+                               accordionElements[a].accordion("activate", -1);
+                               accordionElements[a].hide();
+                               tabElements[a].removeClass("active");
+
+                       }
+               }
+
+               accordionElements[id].accordion("option", "animated", false);
+               accordionElements[id].accordion("activate", refresh ? activeIndex : 0);
+               tabElements[id].addClass("active");
+               accordionElements[id].show();
+               accordionElements[id].accordion("option", "animated", "slide");
+               resetDisplayCanvas();
+       }
+
+       // revert to a previous image state
+       function undo(idx) {
+               var undoImage = undoImages[idx];
+
+               if (!undoImage) 
+                       throw new Error(errorDialog("Invalid undo state"));
+               if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))
+                       throw new Error(errorDialog("$imageCanvas doesn't exist"));
+
+               var canvas = $imageCanvas.get(0);
+               addUndo(canvas);
+               canvas.width = imageWidth = undoImage.width;
+               canvas.height = imageHeight = undoImage.height;
+               canvas.getContext("2d").drawImage(undoImage,0,0);
+
+               enableTab(activeTabId, true);
+               resetDisplayCanvas();
+       }
+
+       function addUndo(canvasElement) {
+               if (!canvasElement)
+                       throw new Error(errorDialog("No undo image state provided"));
+
+               if (undoImages.length == undoLevels) {
+                       undoImages.shift();
+               }
+               var undoCanvas = document.createElement("canvas");
+               undoCanvas.width = canvasElement.width;
+               undoCanvas.height = canvasElement.height;
+               undoCanvas.getContext("2d").drawImage(canvasElement,0,0);
+               $j(undoCanvas).addClass("undo-canvas");
+               undoImages.push(undoCanvas);
+               updateUndoList();
+       }
+
+       function updateUndoList() {
+               var $listCtr = $j("#undo-bar", doc)
+                       .html("");
+
+               var ctrHeight = $listCtr.height();
+
+               var $testCanvas = $j("<canvas></canvas>", doc)
+                       .addClass("undo-canvas-small")
+                       .addClass("far-far-away")
+                       .appendTo("body");
+
+               var canvasHeight = $testCanvas.height();
+               var canvasWidth = $testCanvas.width();
+               var canvasCSSHeight = canvasHeight + parseInt($testCanvas.css("margin-top"),10) + parseInt($testCanvas.css("margin-bottom"),10);
+
+               $testCanvas.remove();
+
+               var undoRatio = canvasWidth / canvasHeight;
+
+               for (var i=undoImages.length-1;i>=0;i--) {
+                       (function(){
+                               var canvas = document.createElement("canvas");
+                               $j(canvas)
+                                       .addClass("undo-canvas-small")
+                                       .attr("width", canvasWidth)
+                                       .attr("height", canvasHeight);
+
+                               var image = undoImages[i];
+                               $j(image).show();
+                               
+                               var undoWidth, undoHeight;
+                               var imageRatio = image.width / image.height;
+
+                               if (imageRatio > undoRatio) {   // image too wide
+                                       undoWidth = canvasWidth;
+                                       undoHeight = canvasWidth / imageRatio;
+                               } else {
+                                       undoWidth = canvasHeight * imageRatio;
+                                       undoHeight = canvasHeight;
+                               }
+
+                               var restWidth = canvasWidth - undoWidth;
+                               var restHeight = canvasHeight - undoHeight;
+
+                               canvas.getContext("2d").drawImage(
+                                       image,
+                                       0,0,image.width,image.height,
+                                       restWidth*0.5, restHeight*0.5,
+                                       undoWidth, undoHeight
+                               );
+
+
+                               $link = $j("<a href='#'></a>", doc)
+                                       .addClass("undo-link")
+                                       .appendTo($listCtr)
+                                       .mouseover(function(){ $j(this).addClass("hover") })
+                                       .mouseout(function(){ $j(this).removeClass("hover") });
+                               $j(canvas).appendTo($link);
+
+                               var displayShowing;
+                               var undoIndex = i;
+                               $link.click(function() {
+                                       $j(image).hide();
+                                       $j(image).remove();
+                                       undo(undoIndex);
+                                       if (displayShowing)
+                                               $displayCanvas.show();
+                                       $j(".jcrop-holder", doc).show();
+                               });
+
+                               $link.mouseover(function() {
+                                       displayShowing = $displayCanvas.css("display") != "none";
+                                       var $imagectr = $j("#image-container", doc);
+
+                                       $j(".jcrop-holder", doc).hide();
+                                       $displayCanvas.hide();
+                                       $j(image).appendTo($imagectr);
+
+                                       var h1 = $j("#image-area", doc).height();
+                                       var h2 = image.height;
+                                       var m = Math.max(0, (h1 - h2) / 2);
+                                       $imagectr.css("marginTop", m);
+                       
+                                       $imagectr.height(image.height);
+                               });
+
+                               $link.mouseout(function() {
+                                       $j(image).remove();
+                                       if (displayShowing)
+                                               $displayCanvas.show();
+                                       $j(".jcrop-holder", doc).show();
+                                       updateDisplayCanvas();
+                               });
+
+
+                               $j(canvas).attr("title", "Click to revert to this previous image");
+
+                       })();
+               }
+       }
+
+
+       function applyAction(id, options, afteraction) {
+               if (!Pixastic.Actions[id])
+                       throw new Error("applyAction(): unknown action [" + id + "]");
+
+               $j("#action-bar-overlay", doc).show();
+
+               setTimeout(function() {
+                       options.leaveDOM = true;
+                       var canvasElement = $imageCanvas.get(0);
+                       addUndo(canvasElement)
+       
+                       var res = Pixastic.process(
+                               canvasElement, id, options,
+                               function(resCanvas) {
+                                       canvasElement.width = imageWidth = resCanvas.width;
+                                       canvasElement.height = imageHeight = resCanvas.height;
+       
+                                       var ctx = canvasElement.getContext("2d");
+                                       ctx.clearRect(0,0,imageWidth,imageHeight);
+                                       ctx.drawImage(resCanvas,0,0);
+                                       $imageCanvas = $j(canvasElement);
+                                       resetDisplayCanvas();
+       
+                                       $j("#action-bar-overlay", doc).hide();
+
+                                       if (afteraction)
+                                               afteraction();
+                               }
+                       );
+                       if (!res)
+                               throw new Error("applyAction(): Pixastic.process() failed for action [" + id + "]");
+               },1);
+       }
+
+
+       function previewAction(id, options, afteraction) {
+               if (!Pixastic.Actions[id])
+                       throw new Error("applyAction(): unknown action [" + id + "]");
+
+               $j("#action-bar-overlay", doc).show();
+
+               resetDisplayCanvas();
+
+               options.leaveDOM = true;
+               var canvasElement = $displayCanvas.get(0);
+
+               var res = Pixastic.process(
+                       canvasElement, id, options,
+                       function(resCanvas) {
+
+                               canvasElement.width = resCanvas.width;
+                               canvasElement.height = resCanvas.height;
+
+                               var ctx = canvasElement.getContext("2d");
+                               ctx.clearRect(0,0,canvasElement.width,canvasElement.height);
+                               ctx.drawImage(resCanvas,0,0);
+                               updateDisplayCanvas();
+                               updateOverlay();
+
+                               $j("#action-bar-overlay", doc).hide();
+
+                               if (afteraction)
+                                       afteraction();
+                       }
+               );
+       }
+
+       var onwindowresize = function() {
+               updateDisplayCanvas();
+               updateOverlay();
+       }
+
+       var baseUrl = ""
+
+       function buildEditor() {
+               var styles = [
+                       "jquery-ui-1.7.1.custom.css",
+                       "jquery.Jcrop.css",
+                       "pixastic.css"
+               ];
+
+               for (var i=0;i<styles.length;i++) {
+                       var s = doc.createElement("link");
+                       s.href = baseUrl + styles[i];
+                       s.type = "text/css";
+                       s.rel = "stylesheet";
+                       doc.getElementsByTagName("head")[0].appendChild( s );
+               }
+
+               undoImages = [];
+               accordionElements = {};
+               tabElements = {};
+               activeTabId = -1;
+               $activeTabContent = null;
+
+               // setup DOM UI skeleton
+               $editor = $j("<div />", doc)
+                       .attr("id", "pixastic-editor")
+                       .appendTo($j(doc.body));
+
+               $editor.append(
+                       $j("<div id='background' />", doc),
+                       $j("<div id='edit-ctr-1' />", doc).append(
+                               $j("<div id='edit-ctr-2' />", doc).append(
+                                       $j("<div id='controls-bar' />", doc).append(
+                                               $j("<div id='action-bar' />", doc).append(
+                                                       $j("<div id='action-bar-overlay' />", doc)
+                                               ),
+                                               $j("<div id='undo-bar' />", doc)
+                                       ),
+                                       $j("<div id='image-area' />", doc).append(
+                                               $j("<div id='image-area-sub' />", doc).append(
+                                                       $j("<div id='image-container' />", doc),
+                                                       $j("<div id='image-overlay-container' />", doc).append(
+                                                               $j("<div id='image-overlay' />", doc)
+                                                       )
+                                               )
+                                       )
+                               )
+                       ),
+                       $j("<div id='main-bar' />", doc),
+                       $j("<div id='powered-by-pixastic'><a href=\"http://www.pixastic.com/\" target=\"_blank\">Powered by Pixastic</a></div>", doc)
+               );
+
+               $j("#image-container", doc).append(
+                       $displayCanvas = $j("<canvas />", doc)
+                               .addClass("display-canvas")
+               );
+
+               // loop through all  defined UI action controls
+               var tabs = PixasticEditor.UI.data.tabs;
+
+               for (var i=0;i<tabs.length;i++) {
+                       (function() {
+       
+                       var tab = tabs[i];
+
+                       var $tabElement = $j("<a href=\"#\">" + tab.title + "</a>", doc)
+                               .attr("id", "main-tab-button-" + tab.id)
+                               .addClass("main-tab")
+                               .click(function() {
+                                       enableTab(tab.id);
+                               })
+                               .mouseover(function(){ $j(this).addClass("hover") })
+                               .mouseout(function(){ $j(this).removeClass("hover") });
+       
+                       $j("#main-bar", doc).append($tabElement);
+
+                       tabElements[tab.id] = $tabElement;
+
+                       var $menu = $j("<div/>", doc);
+                       accordionElements[tab.id] = $menu;
+
+                       for (var j=0;j<tab.actions.length;j++) {
+                               (function() {
+
+                               var action = tab.actions[j];
+
+                               var $actionElement = $j("<div><h3><a href=\"#\">" + action.title + "</a></h3></div>", doc)
+
+                               $menu.append($actionElement);
+
+                               var $content = $j("<div></div>", doc)
+                                       .attr("id", "pixastic-action-tab-content-" + action.id)
+                                       .appendTo($actionElement);
+
+                               var controlOptions = [];
+
+                               action.previewEnabled = false;
+                               if (action.forcePreview)
+                                       action.previewEnabled = true;
+
+                               function togglePreview(enable, doAction) {
+                                       if (enable && !action.previewEnabled && doAction)
+                                               doAction(true);
+                                       if (!enable && action.previewEnabled)
+                                               resetDisplayCanvas();
+                       
+                                       action.previewEnabled = enable;
+                               }
+
+                               var reset = function() {
+                                       for (var i in controlOptions) {
+                                               if (controlOptions.hasOwnProperty(i)) {
+                                                       controlOptions[i].reset();
+                                               }
+                                       }
+                                       if (action.previewEnabled)
+                                               doAction(true);
+                               }
+                               var doAction = function(isPreview) {
+                                       var options = {};
+                                       for (var i in controlOptions) {
+                                               if (controlOptions.hasOwnProperty(i)) {
+                                                       options[i] = controlOptions[i].valueField.val();
+                                               }
+                                       }
+
+                                       var afteraction = function() {
+                                               if (action.onafteraction)
+                                                       action.onafteraction(action, isPreview);
+                                               if (!isPreview)
+                                                       resetDisplayCanvas();
+       
+                                               if (!isPreview && !action.forcePreview) {
+                                                       $j("#pixastic-input-preview-" + action.id, doc).attr("checked", false);
+                                                       togglePreview(false);
+                                                       reset();
+                                               }
+                                       }
+
+                                       if (isPreview) {
+                                               previewAction(action.id, options, afteraction);
+                                       } else {
+                                               applyAction(action.id, options, afteraction);
+                                       }
+
+                               }
+
+                               var hadInputs = false;
+
+                               if (action.controls) {
+                                       var onChange = function() {};
+                                       if (action.isAction && action.preview) {
+                                               onChange = function() {
+                                                       if (action.previewEnabled)
+                                                               doAction(true)
+                                               };
+                                       }
+
+                                       for (var k=0;k<action.controls.length;k++) {
+                                               var control = action.controls[k];
+                                               if (typeof control.defaultValue != "function") {
+                                                       (function(){
+                                                       var defVal = control.defaultValue;
+                                                       control.defaultValue = function() {
+                                                               return defVal;
+                                                       }
+                                                       })();
+                                               }
+                                               var controlId = action.id + "-" + control.option;
+
+                                               if (control.type != "output")
+                                                       hadInputs = true;
+
+                                               switch (control.type) {
+                                                       case "number" :
+                                                               switch (control.ui) {
+                                                                       case "slider" : 
+                                                                               var slider = PixasticEditor.UI.makeSlider(
+                                                                                       control.label, controlId, 
+                                                                                       control.range[0], control.range[1], control.step, control.defaultValue, onChange
+                                                                               );
+               
+                                                                               slider.container.appendTo($content);
+                                                                               controlOptions[control.option] = slider;
+                                                                               break;
+                                                                       case "text" : 
+                                                                               var text = PixasticEditor.UI.makeNumericInput(
+                                                                                       control.label, control.labelRight, controlId, 
+                                                                                       control.range[0], control.range[1], control.step, control.defaultValue, onChange
+                                                                               );
+                                                                               text.container.appendTo($content);
+                                                                               controlOptions[control.option] = text;
+                                                                               break;
+                                                               }
+                                                               break;
+                                                       case "boolean" :
+                                                               switch (control.ui) {
+                                                                       case "checkbox" : 
+                                                                               var checkbox = PixasticEditor.UI.makeCheckbox(
+                                                                                       control.label, controlId, control.defaultValue, onChange
+                                                                               );
+               
+                                                                               checkbox.container.appendTo($content);
+                                                                               controlOptions[control.option] = checkbox;
+                                                                               break;
+                                                               }
+                                                       case "string" :
+                                                               switch (control.ui) {
+                                                                       case "select" : 
+                                                                               var select = PixasticEditor.UI.makeSelect(
+                                                                                       control.label, controlId, control.values, control.defaultValue, onChange
+                                                                               );
+               
+                                                                               select.container.appendTo($content);
+                                                                               controlOptions[control.option] = select;
+                                                                               break;
+                                                               }
+                                                               break;
+                                                       case "output" :
+                                                               var outputText = $j("<div></div>", doc)
+                                                                       .addClass("ui-action-output")
+                                                                       .html(control.content)
+                                                                       .appendTo($content);
+                                                               break;
+                                               }
+                                       }
+                               }
+
+                               if (action.isAction) {
+
+                                       var $applyButton = PixasticEditor.UI.makeButton("Apply")
+                                               .addClass("pixastic-option-button-apply")
+                                               .click(function() {doAction();});
+
+                                       $content.append($applyButton);
+
+                                       if (hadInputs) {
+                                               var $resetButton = PixasticEditor.UI.makeButton("Reset")
+                                                       .addClass("pixastic-option-button-reset")
+                                                       .click(reset);
+       
+                                               $content.append($resetButton)
+                                       }
+
+                                       if (action.preview && !action.forcePreview) {
+                                               var $checkctr = $j("<div></div>", doc)
+                                                       .addClass("ui-checkbox-container")
+                                                       .addClass("ui-preview-checkbox-container");
+
+                                               var $label = $j("<label></label>", doc)
+                                                       .addClass("ui-checkbox-label")
+                                                       .attr("for", "pixastic-input-preview-" + action.id)
+                                                       .html("Preview:")
+                                                       .appendTo($checkctr);
+
+                                               var $checkbox = $j("<input type=\"checkbox\"></input>", doc)
+                                                       .addClass("ui-checkbox")
+                                                       .attr("id", "pixastic-input-preview-" + action.id)
+                                                       .appendTo($checkctr)
+                                                       .change(function() {
+                                                               togglePreview(this.checked, doAction)
+                                                       });
+
+                                               $content.append($checkctr);
+
+                                               $content.data("previewCheckbox", $checkbox);
+                                       }
+
+                               }
+
+
+                               if (typeof action.content == "function") {
+                                       action.content($content);
+                               }
+
+                               // stupid hack to make it possible to get $content in change event (below)
+                               $j("<span></span>", doc).appendTo($content);
+
+                               $content.data("controlOptions", controlOptions);
+                               $content.data("onactivate", action.onactivate);
+                               $content.data("ondeactivate", action.ondeactivate);
+                               $content.data("onoverlayupdate", action.onoverlayupdate);
+                               $content.data("accordionindex", j);
+                               $content.data("uidesc", action);
+
+                               })();
+                       }
+       
+                       $j("#action-bar", doc).append($menu);
+
+                       $menu.hide().accordion({
+                               header: "h3",
+                               autoHeight : false,
+                               collapsible : true,
+                               active: -1
+                       })
+                       .bind("accordionchange", 
+                               function(event, ui) {
+                                       resetDisplayCanvas();
+
+                                       // oldContent / newContent are arrays of whatever elements are present in the content area
+                                       // We need the parent element (the one holding the content) but if there is no content, how do we get it?
+                                       // fixed above by always appending a <span> but that's ugly and needs to be done in some other way
+                                       if (ui.oldContent.get(0)) {
+                                               var $parent = $j(ui.oldContent.get(0).parentNode);
+                                               if ($parent.data("ondeactivate")) {
+                                                       $parent.data("ondeactivate")();
+                                               }
+                                       }
+                                       $activeTabContent = ui.newContent;
+
+                                       if (ui.newContent.get(0)) {
+                                               var $parent = $j(ui.newContent.get(0).parentNode);
+                                               if ($parent.data("previewCheckbox"))
+                                                       $parent.data("previewCheckbox").attr("checked", false);
+                                               $parent.data("uidesc").previewEnabled = false;
+                                               if ($parent.data("uidesc").forcePreview)
+                                                       $parent.data("uidesc").previewEnabled = true;
+
+                                               var controlOptions = $parent.data("controlOptions");
+                                               for (var i in controlOptions) {
+                                                       if (controlOptions.hasOwnProperty(i)) {
+                                                               controlOptions[i].reset();
+                                                       }
+                                               }
+                                               if ($parent.data("onactivate")) {
+                                                       $parent.data("onactivate")();
+                                               }
+                                       }
+                                       updateDisplayCanvas();
+
+                               }
+                       );
+
+       
+                       })();
+               }
+
+               $j(window).bind("resize", onwindowresize);
+       }
+
+       function showLoadingScreen() {
+               if ($loadingScreen) {
+                       $loadingScreen.show();
+                       return;
+               }
+               $loadingScreen = $j("<div id=\"loading-screen\" />")
+               var $ctr = $j("<div id=\"loading-screen-cell\" />");
+               $j("<div />")
+                       .addClass("spinner")
+                       .appendTo($ctr);
+               $loadingScreen.append($ctr);
+               $loadingScreen.appendTo("body");
+       }
+
+       function hideLoadingScreen() {
+               setTimeout(function() {
+                       $loadingScreen.hide();
+               }, 1);
+       }
+
+       var oldScrollLeft;
+       var oldScrollTop;
+       var oldOverflow;
+
+       // fire it up
+       function init(callback) {
+               isRunning = true;
+
+               showLoadingScreen();
+
+               oldScrollLeft = document.body.scrollLeft;
+               oldScrollTop = document.body.scrollTop;
+               oldOverflow = document.body.style.overflow;
+
+               document.body.scrollLeft = 0;
+               document.body.scrollTop = 0;
+               document.body.style.overflow = "hidden";
+
+               $frame = $j("<iframe />");
+               $frame.hide();
+               $frame.css({
+                       position : "absolute",
+                       left : document.body.scrollLeft + "px",
+                       top : document.body.scrollTop + "px",
+                       width : "100%",
+                       height : "100%",
+                       zIndex : "11"
+               });
+               $frame.load(function(){
+                       doc = $frame.get(0).contentDocument;
+
+                       buildEditor();
+                       callback();
+                       $frame.show();
+                       hideLoadingScreen();
+                       setTimeout(function(){
+                               updateDisplayCanvas();
+                       },10);
+               });
+               $frame.appendTo("body");
+       }
+
+       // unload the editor, remove all elements added to the page and restore whatever properties we messed with
+       function unload() {
+               $j(window).unbind("resize", onwindowresize);
+               $frame.hide();
+               $editor.hide();
+               $editor.remove();
+               $frame.remove();
+
+               document.body.scrollLeft = oldScrollLeft;
+               document.body.scrollTop = oldScrollTop;
+               document.body.style.overflow = oldOverflow;
+
+               isRunning = false;
+       }
+
+
+       // resets the display canvas (clears the canvas and repaints the current state)
+       // then updates display and overlay
+       function resetDisplayCanvas() {
+               if (!($displayCanvas && $displayCanvas.get))    throw new Error(errorDialog("$displayCanvas doesn't exist"));
+               if (!($imageCanvas && $imageCanvas.get))        throw new Error(errorDialog("$imageCanvas doesn't exist"));
+
+               var display = $displayCanvas.get(0);
+               var image = $imageCanvas.get(0);
+
+               if (!display)   throw new Error(errorDialog("resetDisplayCanvas(): No elements in $displayCanvas"));
+               if (!image)     throw new Error(errorDialog("resetDisplayCanvas(): No elements in $imageCanvas"));
+
+               display.width = imageWidth;
+               display.height = imageHeight;
+               display.getContext("2d").drawImage( image, 0, 0 );
+
+               updateDisplayCanvas();
+               updateOverlay();
+       }
+
+       // updates the display by resetting the height and margin of the image container
+       // this is mainly to keep vertical centering
+       function updateDisplayCanvas() {
+               var $imageCtr = $j("#image-container", doc);
+               var $editArea = $j("#image-area", doc);
+
+               if (!$imageCtr.get(0))          throw new Error(errorDialog("updateDisplayCanvas(): $imageCtr doesn't exist"));
+               if (!$displayCanvas.get(0))     throw new Error(errorDialog("updateDisplayCanvas(): $displayCanvas doesn't exist"));
+               if (!$editArea.get(0))          throw new Error(errorDialog("updateDisplayCanvas(): $editArea doesn't exist"));
+
+               var h2 = $displayCanvas.get(0).height;
+               var h1 = $j("#image-area", doc).height();
+               var m = Math.max(0, (h1 - h2) / 2);
+               $imageCtr.height(h2);
+               $imageCtr.css("marginTop", m);
+       }
+
+       // basically the same as updateDisplayCanvas but for the image overlay
+       function updateOverlay() {
+               var $overlay = $j("#image-overlay-container", doc);
+               var $imagectr = $j("#image-container", doc);
+               $overlay.height($imagectr.height());
+               $overlay.css("marginTop", $imagectr.css("marginTop"));
+
+               if ($activeTabContent && $activeTabContent.get(0)) {
+                       var $tabContent = $j($activeTabContent.get(0).parentNode);
+                       if (typeof $tabContent.data("onoverlayupdate") == "function")
+                               $tabContent.data("onoverlayupdate")();
+               }
+       }
+
+       var imageIsLoading = false;
+       var originalImageElement;
+       var $tmpImg;
+
+       function loadImage(imgEl) {
+               if (imageIsLoading) 
+                       return;
+
+               imageIsLoading = true;
+
+               originalImageElement = imgEl;
+
+               $imageCanvas = $j("<canvas />", doc);
+               imageCtx = $imageCanvas.get(0).getContext("2d");
+
+               imageWidth = 0;
+               imageHeight = 0;
+               $imageCanvas.attr("width", 0);
+               $imageCanvas.attr("height", 0);
+
+               if (imgEl.tagName.toLowerCase() == "img" && !imgEl._pixasticCanvas) {
+                       var onload = function(el) {
+                               imageWidth = el.offsetWidth;
+                               imageHeight = el.offsetHeight;
+                               $imageCanvas.attr("width", imageWidth);
+                               $imageCanvas.attr("height", imageHeight);
+                               imageCtx.drawImage(el,0,0);
+                               $tmpImg.remove();
+                               imageIsLoading = false;
+                               enableTab("reshape");
+                               setTimeout(function() {
+                                       resetDisplayCanvas();
+                               }, 10);
+                       }
+                       $tmpImg = $j("<img />", doc)
+                               .css("position", "absolute")
+                               .css("left", "-9999px")
+                               .css("top", "-9999px")
+                               .appendTo("body")
+                               .load(function(){onload(this);})
+                               .error(function(){
+                                       throw new Error("Could not load temporary copy image. Is provided image valid?");
+                                       unload();
+                               })
+                               .attr("src", imgEl.src);
+                               if ($tmpImg.attr("complete")) {
+                                       onload($tmpImg.get(0));
+                               }
+               } else {
+                       var $canvas = imgEl._pixasticCanvas || imgEl;
+                       imageWidth = $canvas.attr("width");
+                       imageHeight = $canvas.attr("height");
+                       $imageCanvas.attr("width", imageWidth);
+                       $imageCanvas.attr("height", imageHeight);
+                       imageCtx.drawImage($canvas.get(0), 0, 0);
+                       imageIsLoading = false;
+                       enableTab("reshape");
+                       resetDisplayCanvas();
+               }
+       }
+
+       // return public interface
+       return {
+               /*
+               // don't call. For now we must load the image immediately via load()
+               loadImage : function(imgEl) {
+                       if (!isRunning) return false;
+                       loadImage(imgEl);
+               },
+               */
+               saveToPage : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::saveToPage(): Editor is not running");
+
+                       var $canvas = PixasticEditor.getImageCanvas();
+                       var img = PixasticEditor.getOriginalImage();
+                       if (img.tagName.toLowerCase() == "canvas") {
+                               img.width = $canvas.attr("width");
+                               img.height = $canvas.attr("height");
+                               img.getContext("2d").drawImage($canvas.get(0), 0, 0);
+                       } else {
+                               img.src = PixasticEditor.getDataURI();
+                       }
+                       img._pixasticCanvas = PixasticEditor.getImageCanvas();
+               },
+               load : function(img, customBaseUrl) {
+                       if (isRunning) return false;
+
+                       if (!img)
+                               throw new Error("Must be called with an image or canvas as its first argument", "PixasticEditor::load")
+
+                       $ = PixasticEditor.jQuery;
+
+                       baseUrl = customBaseUrl || "http://www.pixastic.com/editor-test/";
+
+                       init(function() {
+                               if (img && img.tagName.toLowerCase() == "img" || img.tagName.toLowerCase() == "canvas") {
+                                       loadImage(img);
+                               }
+                       });
+               },
+
+               unload : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::unload(): Editor is not running");
+                       unload();
+               },
+
+               getDocument : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getDocument(): Editor is not running");
+
+                       return doc;
+               },
+
+               validSaveFormats : function() {
+                       return saveFormats;
+               },
+
+               getOriginalImage : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getOriginalImage(): Editor is not running");
+                       return originalImageElement;
+               },
+
+               getDataURI : function(mime) {
+                       if (!isRunning) throw new Error("PixasticEditor::getDataURI(): Editor is not running");
+
+                       if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))
+                               throw new Error(errorDialog("$imageCanvas doesn't exist", "getImageCanvas"));
+
+                       return $imageCanvas.get(0).toDataURL(mime||"image/png");
+               },
+
+               getImageCanvas : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getImageCanvas(): Editor is not running");
+
+                       if (!($imageCanvas && $imageCanvas.get && $imageCanvas.get(0)))
+                               throw new Error(errorDialog("$imageCanvas doesn't exist", "getImageCanvas"));
+
+                       return $imageCanvas;
+               },
+               getOverlay : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getOverlay(): Editor is not running");
+
+                       return $j("#image-overlay", doc);
+               },
+               getDisplayCanvas : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getDisplayCanvas(): Editor is not running");
+
+                       if (!($displayCanvas && $displayCanvas.get && $displayCanvas.get(0)))
+                               throw new Error(errorDialog("$displayCanvas doesn't exist", "getDisplayCanvas"));
+                       return $displayCanvas;
+               },
+               getDisplayWidth : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getDisplayWidth(): Editor is not running");
+
+                       return displayWidth;
+               },
+               getDisplayHeight : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getDisplayHeight(): Editor is not running");
+
+                       return displayHeight;
+               },
+               getImageWidth : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getImageWidth(): Editor is not running");
+
+                       return imageWidth;
+               },
+               getImageHeight : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::getImageHeight(): Editor is not running");
+
+                       return imageHeight;
+               },
+               errorDialog : function() {
+                       if (!isRunning) throw new Error("PixasticEditor::errorDialog(): Editor is not running");
+
+                       return errorDialog.apply(null, arguments);
+               }
+       }
+
 })();
\ No newline at end of file
index fa38d04..bee153a 100644 (file)
-/*\r
- * Pixastic Lib - Core Functions - v0.1.3\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-var Pixastic = (function() {\r
-\r
-\r
-       function addEvent(el, event, handler) {\r
-               if (el.addEventListener)\r
-                       el.addEventListener(event, handler, false); \r
-               else if (el.attachEvent)\r
-                       el.attachEvent("on" + event, handler); \r
-       }\r
-\r
-       function onready(handler) {\r
-               var handlerDone = false;\r
-               var execHandler = function() {\r
-                       if (!handlerDone) {\r
-                               handlerDone = true;\r
-                               handler();\r
-                       }\r
-               }\r
-               document.write("<"+"script defer src=\"//:\" id=\"__onload_ie_sumbox__\"></"+"script>");\r
-               var script = document.getElementById("__onload_ie_sumbox__");\r
-               script.onreadystatechange = function() {\r
-                       if (script.readyState == "complete") {\r
-                               script.parentNode.removeChild(script);\r
-                               execHandler();\r
-                       }\r
-               }\r
-               if (document.addEventListener)\r
-                       document.addEventListener("DOMContentLoaded", execHandler, false); \r
-               addEvent(window, "load", execHandler);\r
-       }\r
-\r
-       function init() {\r
-               if (!Pixastic.parseOnLoad) return;\r
-               var imgEls = getElementsByClass("pixastic", null, "img");\r
-               var canvasEls = getElementsByClass("pixastic", null, "canvas");\r
-               var elements = imgEls.concat(canvasEls);\r
-               for (var i=0;i<elements.length;i++) {\r
-                       (function() {\r
-\r
-                       var el = elements[i];\r
-                       var actions = [];\r
-                       var classes = el.className.split(" ");\r
-                       for (var c=0;c<classes.length;c++) {\r
-                               var cls = classes[c];\r
-                               if (cls.substring(0,9) == "pixastic-") {\r
-                                       var actionName = cls.substring(9);\r
-                                       if (actionName != "")\r
-                                               actions.push(actionName);\r
-                               }\r
-                       }\r
-                       if (actions.length) {\r
-                               if (el.tagName.toLowerCase() == "img") {\r
-                                       var dataImg = new Image();\r
-                                       dataImg.src = el.src;\r
-                                       if (dataImg.complete) {\r
-                                               for (var a=0;a<actions.length;a++) {\r
-                                                       var res = Pixastic.applyAction(el, el, actions[a], null);\r
-                                                       if (res) \r
-                                                               el = res;\r
-                                               }\r
-                                       } else {\r
-                                               dataImg.onload = function() {\r
-                                                       for (var a=0;a<actions.length;a++) {\r
-                                                               var res = Pixastic.applyAction(el, el, actions[a], null)\r
-                                                               if (res) \r
-                                                                       el = res;\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                               } else {\r
-                                       setTimeout(function() {\r
-                                               for (var a=0;a<actions.length;a++) {\r
-                                                       var res = Pixastic.applyAction(\r
-                                                               el, el, actions[a], null\r
-                                                       );\r
-                                                       if (res) \r
-                                                               el = res;\r
-                                               }\r
-                                       },1);\r
-                               }\r
-                       }\r
-\r
-                       })();\r
-               }\r
-       }\r
-\r
-//     if (typeof pixastic_no_onready == "undefined") // yuck.\r
-//             onready(init);\r
-\r
-       // getElementsByClass by Dustin Diaz, http://www.dustindiaz.com/getelementsbyclass/\r
-       function getElementsByClass(searchClass,node,tag) {\r
-               var classElements = new Array();\r
-               if ( node == null )\r
-                       node = document;\r
-               if ( tag == null )\r
-                       tag = '*';\r
-\r
-               var els = node.getElementsByTagName(tag);\r
-               var elsLen = els.length;\r
-               var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");\r
-               for (i = 0, j = 0; i < elsLen; i++) {\r
-                       if ( pattern.test(els[i].className) ) {\r
-                               classElements[j] = els[i];\r
-                               j++;\r
-                       }\r
-               }\r
-               return classElements;\r
-       }\r
-\r
-       var debugElement;\r
-\r
-       function writeDebug(text, level) {\r
-               if (!Pixastic.debug) return;\r
-               try {\r
-                       switch (level) {\r
-                               case "warn" : \r
-                                       console.warn("Pixastic:", text);\r
-                                       break;\r
-                               case "error" :\r
-                                       console.error("Pixastic:", text);\r
-                                       break;\r
-                               default:\r
-                                       console.log("Pixastic:", text);\r
-                       }\r
-               } catch(e) {\r
-               }\r
-               if (!debugElement) {\r
-                       \r
-               }\r
-       }\r
-\r
-\r
-       return {\r
-\r
-               parseOnLoad : false,\r
-\r
-               debug : false,\r
-               \r
-               applyAction : function(img, dataImg, actionName, options) {\r
-\r
-                       options = options || {};\r
-\r
-                       var imageIsCanvas = (img.tagName.toLowerCase() == "canvas");\r
-                       if (imageIsCanvas && Pixastic.Client.isIE()) {\r
-                               if (Pixastic.debug) writeDebug("Tried to process a canvas element but browser is IE.");\r
-                               return false;\r
-                       }\r
-\r
-                       var canvas, ctx;\r
-                       if (Pixastic.Client.hasCanvas()) {\r
-                               canvas = document.createElement("canvas");\r
-                               ctx = canvas.getContext("2d");\r
-                       }\r
-\r
-                       var w = parseInt(img.offsetWidth);\r
-                       var h = parseInt(img.offsetHeight);\r
-\r
-                       if (imageIsCanvas) {\r
-                               w = img.width;\r
-                               h = img.height;\r
-                       }\r
-\r
-                       if (actionName.indexOf("(") > -1) {\r
-                               var tmp = actionName;\r
-                               actionName = tmp.substr(0, tmp.indexOf("("));\r
-                               var arg = tmp.match(/\((.*?)\)/);\r
-                               if (arg[1]) {\r
-                                       arg = arg[1].split(";");\r
-                                       for (var a=0;a<arg.length;a++) {\r
-                                               thisArg = arg[a].split("=");\r
-                                               if (thisArg.length == 2) {\r
-                                                       if (thisArg[0] == "rect") {\r
-                                                               var rectVal = thisArg[1].split(",");\r
-                                                               options[thisArg[0]] = {\r
-                                                                       left : parseInt(rectVal[0],10)||0,\r
-                                                                       top : parseInt(rectVal[1],10)||0,\r
-                                                                       width : parseInt(rectVal[2],10)||0,\r
-                                                                       height : parseInt(rectVal[3],10)||0\r
-                                                               }\r
-                                                       } else {\r
-                                                               options[thisArg[0]] = thisArg[1];\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-\r
-                       if (!options.rect) {\r
-                               options.rect = {\r
-                                       left : 0, top : 0, width : w, height : h\r
-                               };\r
-                       }\r
-                       var validAction = false;\r
-                       if (Pixastic.Actions[actionName] && typeof Pixastic.Actions[actionName].process == "function") {\r
-                               validAction = true;\r
-                       }\r
-                       if (!validAction) {\r
-                               if (Pixastic.debug) writeDebug("Invalid action \"" + actionName + "\". Maybe file not included?");\r
-                               return false;\r
-                       }\r
-                       if (!Pixastic.Actions[actionName].checkSupport()) {\r
-                               if (Pixastic.debug) writeDebug("Action \"" + actionName + "\" not supported by this browser.");\r
-                               return false;\r
-                       }\r
-\r
-                       if (Pixastic.Client.hasCanvas()) {\r
-                               canvas.width = w;\r
-                               canvas.height = h;\r
-                               canvas.style.width = w+"px";\r
-                               canvas.style.height = h+"px";\r
-                               ctx.drawImage(dataImg,0,0,w,h);\r
-\r
-                               if (!img.__pixastic_org_image) {\r
-                                       canvas.__pixastic_org_image = img;\r
-                                       canvas.__pixastic_org_width = w;\r
-                                       canvas.__pixastic_org_height = h;\r
-                               } else {\r
-                                       canvas.__pixastic_org_image = img.__pixastic_org_image;\r
-                                       canvas.__pixastic_org_width = img.__pixastic_org_width;\r
-                                       canvas.__pixastic_org_height = img.__pixastic_org_height;\r
-                               }\r
-\r
-                       } else if (Pixastic.Client.isIE() && typeof img.__pixastic_org_style == "undefined") {\r
-                               img.__pixastic_org_style = img.style.cssText;\r
-                       }\r
-\r
-                       var params = {\r
-                               image : img,\r
-                               canvas : canvas,\r
-                               width : w,\r
-                               height : h,\r
-                               useData : true,\r
-                               options : options\r
-                       }\r
-\r
-                       // Ok, let's do it!\r
-\r
-                       var res = Pixastic.Actions[actionName].process(params);\r
-\r
-                       if (!res) {\r
-                               return false;\r
-                       }\r
-\r
-                       if (Pixastic.Client.hasCanvas()) {\r
-                               if (params.useData) {\r
-                                       if (Pixastic.Client.hasCanvasImageData()) {\r
-                                               canvas.getContext("2d").putImageData(params.canvasData, options.rect.left, options.rect.top);\r
-\r
-                                               // Opera doesn't seem to update the canvas until we draw something on it, lets draw a 0x0 rectangle.\r
-                                               canvas.getContext("2d").fillRect(0,0,0,0);\r
-                                       }\r
-                               }\r
-\r
-                               if (!options.leaveDOM) {\r
-                                       // copy properties and stuff from the source image\r
-                                       canvas.title = img.title;\r
-                                       canvas.imgsrc = img.imgsrc;\r
-                                       if (!imageIsCanvas) canvas.alt  = img.alt;\r
-                                       if (!imageIsCanvas) canvas.imgsrc = img.src;\r
-                                       canvas.className = img.className;\r
-                                       canvas.style.cssText = img.style.cssText;\r
-                                       canvas.name = img.name;\r
-                                       canvas.tabIndex = img.tabIndex;\r
-                                       canvas.id = img.id;\r
-                                       if (img.parentNode && img.parentNode.replaceChild) {\r
-                                               img.parentNode.replaceChild(canvas, img);\r
-                                       }\r
-                               }\r
-\r
-                               options.resultCanvas = canvas;\r
-\r
-                               return canvas;\r
-                       }\r
-\r
-                       return img;\r
-               },\r
-\r
-               prepareData : function(params, getCopy) {\r
-                       var ctx = params.canvas.getContext("2d");\r
-                       var rect = params.options.rect;\r
-                       var dataDesc = ctx.getImageData(rect.left, rect.top, rect.width, rect.height);\r
-                       var data = dataDesc.data;\r
-                       if (!getCopy) params.canvasData = dataDesc;\r
-                       return data;\r
-               },\r
-\r
-               // load the image file\r
-               process : function(img, actionName, options, callback)\r
-               {\r
-                       if (img.tagName.toLowerCase() == "img") {\r
-                               var dataImg = new Image();\r
-                               dataImg.src = img.src;\r
-                               if (dataImg.complete) {\r
-                                       var res = Pixastic.applyAction(img, dataImg, actionName, options);\r
-                                       if (callback) callback(res);\r
-                                       return res;\r
-                               } else {\r
-                                       dataImg.onload = function() {\r
-                                               var res = Pixastic.applyAction(img, dataImg, actionName, options)\r
-                                               if (callback) callback(res);\r
-                                       }\r
-                               }\r
-                       }\r
-                       if (img.tagName.toLowerCase() == "canvas") {\r
-                               var res = Pixastic.applyAction(img, img, actionName, options);\r
-                               if (callback) callback(res);\r
-                               return res;\r
-                       }\r
-               },\r
-\r
-               revert : function(img) {\r
-                       if (Pixastic.Client.hasCanvas()) {\r
-                               if (img.tagName.toLowerCase() == "canvas" && img.__pixastic_org_image) {\r
-                                       img.width = img.__pixastic_org_width;\r
-                                       img.height = img.__pixastic_org_height;\r
-                                       img.getContext("2d").drawImage(img.__pixastic_org_image, 0, 0);\r
-\r
-                                       if (img.parentNode && img.parentNode.replaceChild) {\r
-                                               img.parentNode.replaceChild(img.__pixastic_org_image, img);\r
-                                       }\r
-\r
-                                       return img;\r
-                               }\r
-                       } else if (Pixastic.Client.isIE() && typeof img.__pixastic_org_style != "undefined") {\r
-                               img.style.cssText = img.__pixastic_org_style;\r
-                       }\r
-               },\r
-\r
-               Client : {\r
-                       hasCanvas : (function() {\r
-                               var c = document.createElement("canvas");\r
-                               var val = false;\r
-                               try {\r
-                                       val = !!((typeof c.getContext == "function") && c.getContext("2d"));\r
-                               } catch(e) {}\r
-                               return function() {\r
-                                       return val;\r
-                               }\r
-                       })(),\r
-\r
-                       hasCanvasImageData : (function() {\r
-                               var c = document.createElement("canvas");\r
-                               var val = false;\r
-                               var ctx;\r
-                               try {\r
-                                       if (typeof c.getContext == "function" && (ctx = c.getContext("2d"))) {\r
-                                               val = (typeof ctx.getImageData == "function");\r
-                                       }\r
-                               } catch(e) {}\r
-                               return function() {\r
-                                       return val;\r
-                               }\r
-                       })(),\r
-\r
-                       isIE : function() {\r
-                               return !!document.all && !!window.attachEvent && !window.opera;\r
-                       }\r
-               },\r
-\r
-               Actions : {}\r
-       }\r
-\r
-\r
-})();\r
-/*\r
- * Pixastic Lib - jQuery plugin\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-if (typeof jQuery != "undefined" && jQuery && jQuery.fn) {\r
-       jQuery.fn.pixastic = function(action, options) {\r
-               var newElements = [];\r
-               this.each(\r
-                       function () {\r
-                               if (this.tagName.toLowerCase() == "img" && !this.complete) {\r
-                                       return;\r
-                               }\r
-                               var res = Pixastic.process(this, action, options);\r
-                               if (res) {\r
-                                       newElements.push(res);\r
-                               }\r
-                       }\r
-               );\r
-               if (newElements.length > 0)\r
-                       return jQuery(newElements);\r
-               else\r
-                       return this;\r
-       };\r
-\r
-};\r
-/*\r
- * Pixastic Lib - Blend - v0.1.1\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.blend = {\r
-\r
-       process : function(params) {\r
-               var amount = parseFloat(params.options.amount);\r
-               var mode = (params.options.mode || "normal").toLowerCase();\r
-               var image = params.options.image;\r
-\r
-               amount = Math.max(0,Math.min(1,amount));\r
-\r
-               if (!image) return false;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var rect = params.options.rect;\r
-                       var data = Pixastic.prepareData(params);\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       params.useData = false;\r
-\r
-                       var otherCanvas = document.createElement("canvas");\r
-                       otherCanvas.width = params.canvas.width;\r
-                       otherCanvas.height = params.canvas.height;\r
-                       var otherCtx = otherCanvas.getContext("2d");\r
-                       otherCtx.drawImage(image,0,0);\r
-\r
-                       var params2 = {canvas:otherCanvas,options:params.options};\r
-                       var data2 = Pixastic.prepareData(params2);\r
-                       var dataDesc2 = params2.canvasData;\r
-\r
-                       var p = w*h;\r
-                       var pix = p*4;\r
-                       var pix1, pix2;\r
-                       var r1, g1, b1;\r
-                       var r2, g2, b2;\r
-                       var r3, g3, b3;\r
-                       var r4, g4, b4;\r
-\r
-                       var dataChanged = false;\r
-\r
-                       switch (mode) {\r
-                               case "normal" : \r
-                                       //while (p--) {\r
-                                       //      data2[pix-=4] = data2[pix];\r
-                                       //      data2[pix1=pix+1] = data2[pix1];\r
-                                       //      data2[pix2=pix+2] = data2[pix2];\r
-                                       //}\r
-                                       break;\r
-\r
-                               case "multiply" : \r
-                                       while (p--) {\r
-                                               data2[pix-=4] = data[pix] * data2[pix] / 255;\r
-                                               data2[pix1=pix+1] = data[pix1] * data2[pix1] / 255;\r
-                                               data2[pix2=pix+2] = data[pix2] * data2[pix2] / 255;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "lighten" : \r
-                                       while (p--) {\r
-                                               if ((r1 = data[pix-=4]) > data2[pix])\r
-                                                       data2[pix] = r1;\r
-                                               if ((g1 = data[pix1=pix+1]) > data2[pix1])\r
-                                                       data2[pix1] = g1;\r
-                                               if ((b1 = data[pix2=pix+2]) > data2[pix2])\r
-                                                       data2[pix2] = b1;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "darken" : \r
-                                       while (p--) {\r
-                                               if ((r1 = data[pix-=4]) < data2[pix])\r
-                                                       data2[pix] = r1;\r
-                                               if ((g1 = data[pix1=pix+1]) < data2[pix1])\r
-                                                       data2[pix1] = g1;\r
-                                               if ((b1 = data[pix2=pix+2]) < data2[pix2])\r
-                                                       data2[pix2] = b1;\r
-\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "darkercolor" : \r
-                                       while (p--) {\r
-                                               if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) <= (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {\r
-                                                       data2[pix] = r1;\r
-                                                       data2[pix1] = g1;\r
-                                                       data2[pix2] = b1;\r
-                                               }\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "lightercolor" : \r
-                                       while (p--) {\r
-                                               if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) > (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {\r
-                                                       data2[pix] = r1;\r
-                                                       data2[pix1] = g1;\r
-                                                       data2[pix2] = b1;\r
-                                               }\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "lineardodge" : \r
-                                       otherCtx.globalCompositeOperation = "source-over";\r
-                                       otherCtx.drawImage(params.canvas, 0, 0);\r
-                                       otherCtx.globalCompositeOperation = "lighter";\r
-                                       otherCtx.drawImage(image, 0, 0);\r
-\r
-                                       /*\r
-                                       while (p--) {\r
-                                               if ((r3 = data[pix-=4] + data2[pix]) > 255)\r
-                                                       data2[pix] = 255;\r
-                                               else\r
-                                                       data2[pix] = r3;\r
-                                               if ((g3 = data[pix1=pix+1] + data2[pix1]) > 255)\r
-                                                       data2[pix1] = 255;\r
-                                               else\r
-                                                       data2[pix1] = g3;\r
-                                               if ((b3 = data[pix2=pix+2] + data2[pix2]) > 255)\r
-                                                       data2[pix2] = 255;\r
-                                               else\r
-                                                       data2[pix2] = b3;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       */\r
-\r
-                                       break;\r
-\r
-                               case "linearburn" : \r
-                                       while (p--) {\r
-                                               if ((r3 = data[pix-=4] + data2[pix]) < 255)\r
-                                                       data2[pix] = 0;\r
-                                               else\r
-                                                       data2[pix] = (r3 - 255);\r
-                                               if ((g3 = data[pix1=pix+1] + data2[pix1]) < 255)\r
-                                                       data2[pix1] = 0;\r
-                                               else\r
-                                                       data2[pix1] = (g3 - 255);\r
-                                               if ((b3 = data[pix2=pix+2] + data2[pix2]) < 255)\r
-                                                       data2[pix2] = 0;\r
-                                               else\r
-                                                       data2[pix2] = (b3 - 255);\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "difference" : \r
-                                       while (p--) {\r
-                                               if ((r3 = data[pix-=4] - data2[pix]) < 0)\r
-                                                       data2[pix] = -r3;\r
-                                               else\r
-                                                       data2[pix] = r3;\r
-                                               if ((g3 = data[pix1=pix+1] - data2[pix1]) < 0)\r
-                                                       data2[pix1] = -g3;\r
-                                               else\r
-                                                       data2[pix1] = g3;\r
-                                               if ((b3 = data[pix2=pix+2] - data2[pix2]) < 0)\r
-                                                       data2[pix2] = -b3;\r
-                                               else\r
-                                                       data2[pix2] = b3;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "screen" : \r
-                                       while (p--) {\r
-                                               data2[pix-=4] = (255 - ( ((255-data2[pix])*(255-data[pix])) >> 8));\r
-                                               data2[pix1=pix+1] = (255 - ( ((255-data2[pix1])*(255-data[pix1])) >> 8));\r
-                                               data2[pix2=pix+2] = (255 - ( ((255-data2[pix2])*(255-data[pix2])) >> 8));\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "exclusion" : \r
-                                       var div_2_255 = 2 / 255;\r
-                                       while (p--) {\r
-                                               data2[pix-=4] = (r1 = data[pix]) - (r1 * div_2_255 - 1) * data2[pix];\r
-                                               data2[pix1=pix+1] = (g1 = data[pix1]) - (g1 * div_2_255 - 1) * data2[pix1];\r
-                                               data2[pix2=pix+2] = (b1 = data[pix2]) - (b1 * div_2_255 - 1) * data2[pix2];\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "overlay" : \r
-                                       var div_2_255 = 2 / 255;\r
-                                       while (p--) {\r
-                                               if ((r1 = data[pix-=4]) < 128)\r
-                                                       data2[pix] = data2[pix]*r1*div_2_255;\r
-                                               else\r
-                                                       data2[pix] = 255 - (255-data2[pix])*(255-r1)*div_2_255;\r
-\r
-                                               if ((g1 = data[pix1=pix+1]) < 128)\r
-                                                       data2[pix1] = data2[pix1]*g1*div_2_255;\r
-                                               else\r
-                                                       data2[pix1] = 255 - (255-data2[pix1])*(255-g1)*div_2_255;\r
-\r
-                                               if ((b1 = data[pix2=pix+2]) < 128)\r
-                                                       data2[pix2] = data2[pix2]*b1*div_2_255;\r
-                                               else\r
-                                                       data2[pix2] = 255 - (255-data2[pix2])*(255-b1)*div_2_255;\r
-\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "softlight" : \r
-                                       var div_2_255 = 2 / 255;\r
-                                       while (p--) {\r
-                                               if ((r1 = data[pix-=4]) < 128)\r
-                                                       data2[pix] = ((data2[pix]>>1) + 64) * r1 * div_2_255;\r
-                                               else\r
-                                                       data2[pix] = 255 - (191 - (data2[pix]>>1)) * (255-r1) * div_2_255;\r
-\r
-                                               if ((g1 = data[pix1=pix+1]) < 128)\r
-                                                       data2[pix1] = ((data2[pix1]>>1)+64) * g1 * div_2_255;\r
-                                               else\r
-                                                       data2[pix1] = 255 - (191 - (data2[pix1]>>1)) * (255-g1) * div_2_255;\r
-\r
-                                               if ((b1 = data[pix2=pix+2]) < 128)\r
-                                                       data2[pix2] = ((data2[pix2]>>1)+64) * b1 * div_2_255;\r
-                                               else\r
-                                                       data2[pix2] = 255 - (191 - (data2[pix2]>>1)) * (255-b1) * div_2_255;\r
-\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "hardlight" : \r
-                                       var div_2_255 = 2 / 255;\r
-                                       while (p--) {\r
-                                               if ((r2 = data2[pix-=4]) < 128)\r
-                                                       data2[pix] = data[pix] * r2 * div_2_255;\r
-                                               else\r
-                                                       data2[pix] = 255 - (255-data[pix]) * (255-r2) * div_2_255;\r
-\r
-                                               if ((g2 = data2[pix1=pix+1]) < 128)\r
-                                                       data2[pix1] = data[pix1] * g2 * div_2_255;\r
-                                               else\r
-                                                       data2[pix1] = 255 - (255-data[pix1]) * (255-g2) * div_2_255;\r
-\r
-                                               if ((b2 = data2[pix2=pix+2]) < 128)\r
-                                                       data2[pix2] = data[pix2] * b2 * div_2_255;\r
-                                               else\r
-                                                       data2[pix2] = 255 - (255-data[pix2]) * (255-b2) * div_2_255;\r
-\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "colordodge" : \r
-                                       while (p--) {\r
-                                               if ((r3 = (data[pix-=4]<<8)/(255-(r2 = data2[pix]))) > 255 || r2 == 255)\r
-                                                       data2[pix] = 255;\r
-                                               else\r
-                                                       data2[pix] = r3;\r
-\r
-                                               if ((g3 = (data[pix1=pix+1]<<8)/(255-(g2 = data2[pix1]))) > 255 || g2 == 255)\r
-                                                       data2[pix1] = 255;\r
-                                               else\r
-                                                       data2[pix1] = g3;\r
-\r
-                                               if ((b3 = (data[pix2=pix+2]<<8)/(255-(b2 = data2[pix2]))) > 255 || b2 == 255)\r
-                                                       data2[pix2] = 255;\r
-                                               else\r
-                                                       data2[pix2] = b3;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "colorburn" : \r
-                                       while (p--) {\r
-                                               if ((r3 = 255-((255-data[pix-=4])<<8)/data2[pix]) < 0 || data2[pix] == 0)\r
-                                                       data2[pix] = 0;\r
-                                               else\r
-                                                       data2[pix] = r3;\r
-\r
-                                               if ((g3 = 255-((255-data[pix1=pix+1])<<8)/data2[pix1]) < 0 || data2[pix1] == 0)\r
-                                                       data2[pix1] = 0;\r
-                                               else\r
-                                                       data2[pix1] = g3;\r
-\r
-                                               if ((b3 = 255-((255-data[pix2=pix+2])<<8)/data2[pix2]) < 0 || data2[pix2] == 0)\r
-                                                       data2[pix2] = 0;\r
-                                               else\r
-                                                       data2[pix2] = b3;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "linearlight" : \r
-                                       while (p--) {\r
-                                               if ( ((r3 = 2*(r2=data2[pix-=4])+data[pix]-256) < 0) || (r2 < 128 && r3 < 0)) {\r
-                                                       data2[pix] = 0\r
-                                               } else {\r
-                                                       if (r3 > 255)\r
-                                                               data2[pix] = 255;\r
-                                                       else\r
-                                                               data2[pix] = r3;\r
-                                               }\r
-                                               if ( ((g3 = 2*(g2=data2[pix1=pix+1])+data[pix1]-256) < 0) || (g2 < 128 && g3 < 0)) {\r
-                                                       data2[pix1] = 0\r
-                                               } else {\r
-                                                       if (g3 > 255)\r
-                                                               data2[pix1] = 255;\r
-                                                       else\r
-                                                               data2[pix1] = g3;\r
-                                               }\r
-                                               if ( ((b3 = 2*(b2=data2[pix2=pix+2])+data[pix2]-256) < 0) || (b2 < 128 && b3 < 0)) {\r
-                                                       data2[pix2] = 0\r
-                                               } else {\r
-                                                       if (b3 > 255)\r
-                                                               data2[pix2] = 255;\r
-                                                       else\r
-                                                               data2[pix2] = b3;\r
-                                               }\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "vividlight" : \r
-                                       while (p--) {\r
-                                               if ((r2=data2[pix-=4]) < 128) {\r
-                                                       if (r2) {\r
-                                                               if ((r3 = 255 - ((255-data[pix])<<8) / (2*r2)) < 0) \r
-                                                                       data2[pix] = 0;\r
-                                                               else\r
-                                                                       data2[pix] = r3\r
-                                                       } else {\r
-                                                               data2[pix] = 0;\r
-                                                       }\r
-                                               } else if ((r3 = (r4=2*r2-256)) < 255) {\r
-                                                       if ((r3 = (data[pix]<<8)/(255-r4)) > 255) \r
-                                                               data2[pix] = 255;\r
-                                                       else\r
-                                                               data2[pix] = r3;\r
-                                               } else {\r
-                                                       if (r3 < 0) \r
-                                                               data2[pix] = 0;\r
-                                                       else\r
-                                                               data2[pix] = r3\r
-                                               }\r
-\r
-                                               if ((g2=data2[pix1=pix+1]) < 128) {\r
-                                                       if (g2) {\r
-                                                               if ((g3 = 255 - ((255-data[pix1])<<8) / (2*g2)) < 0) \r
-                                                                       data2[pix1] = 0;\r
-                                                               else\r
-                                                                       data2[pix1] = g3;\r
-                                                       } else {\r
-                                                               data2[pix1] = 0;\r
-                                                       }\r
-                                               } else if ((g3 = (g4=2*g2-256)) < 255) {\r
-                                                       if ((g3 = (data[pix1]<<8)/(255-g4)) > 255)\r
-                                                               data2[pix1] = 255;\r
-                                                       else\r
-                                                               data2[pix1] = g3;\r
-                                               } else {\r
-                                                       if (g3 < 0) \r
-                                                               data2[pix1] = 0;\r
-                                                       else\r
-                                                               data2[pix1] = g3;\r
-                                               }\r
-\r
-                                               if ((b2=data2[pix2=pix+2]) < 128) {\r
-                                                       if (b2) {\r
-                                                               if ((b3 = 255 - ((255-data[pix2])<<8) / (2*b2)) < 0) \r
-                                                                       data2[pix2] = 0;\r
-                                                               else\r
-                                                                       data2[pix2] = b3;\r
-                                                       } else {\r
-                                                               data2[pix2] = 0;\r
-                                                       }\r
-                                               } else if ((b3 = (b4=2*b2-256)) < 255) {\r
-                                                       if ((b3 = (data[pix2]<<8)/(255-b4)) > 255) \r
-                                                               data2[pix2] = 255;\r
-                                                       else\r
-                                                               data2[pix2] = b3;\r
-                                               } else {\r
-                                                       if (b3 < 0) \r
-                                                               data2[pix2] = 0;\r
-                                                       else\r
-                                                               data2[pix2] = b3;\r
-                                               }\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "pinlight" : \r
-                                       while (p--) {\r
-                                               if ((r2=data2[pix-=4]) < 128)\r
-                                                       if ((r1=data[pix]) < (r4=2*r2))\r
-                                                               data2[pix] = r1;\r
-                                                       else\r
-                                                               data2[pix] = r4;\r
-                                               else\r
-                                                       if ((r1=data[pix]) > (r4=2*r2-256))\r
-                                                               data2[pix] = r1;\r
-                                                       else\r
-                                                               data2[pix] = r4;\r
-\r
-                                               if ((g2=data2[pix1=pix+1]) < 128)\r
-                                                       if ((g1=data[pix1]) < (g4=2*g2))\r
-                                                               data2[pix1] = g1;\r
-                                                       else\r
-                                                               data2[pix1] = g4;\r
-                                               else\r
-                                                       if ((g1=data[pix1]) > (g4=2*g2-256))\r
-                                                               data2[pix1] = g1;\r
-                                                       else\r
-                                                               data2[pix1] = g4;\r
-\r
-                                               if ((r2=data2[pix2=pix+2]) < 128)\r
-                                                       if ((r1=data[pix2]) < (r4=2*r2))\r
-                                                               data2[pix2] = r1;\r
-                                                       else\r
-                                                               data2[pix2] = r4;\r
-                                               else\r
-                                                       if ((r1=data[pix2]) > (r4=2*r2-256))\r
-                                                               data2[pix2] = r1;\r
-                                                       else\r
-                                                               data2[pix2] = r4;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-\r
-                               case "hardmix" : \r
-                                       while (p--) {\r
-                                               if ((r2 = data2[pix-=4]) < 128)\r
-                                                       if (255 - ((255-data[pix])<<8)/(2*r2) < 128 || r2 == 0)\r
-                                                               data2[pix] = 0;\r
-                                                       else\r
-                                                               data2[pix] = 255;\r
-                                               else if ((r4=2*r2-256) < 255 && (data[pix]<<8)/(255-r4) < 128)\r
-                                                       data2[pix] = 0;\r
-                                               else\r
-                                                       data2[pix] = 255;\r
-\r
-                                               if ((g2 = data2[pix1=pix+1]) < 128)\r
-                                                       if (255 - ((255-data[pix1])<<8)/(2*g2) < 128 || g2 == 0)\r
-                                                               data2[pix1] = 0;\r
-                                                       else\r
-                                                               data2[pix1] = 255;\r
-                                               else if ((g4=2*g2-256) < 255 && (data[pix1]<<8)/(255-g4) < 128)\r
-                                                       data2[pix1] = 0;\r
-                                               else\r
-                                                       data2[pix1] = 255;\r
-\r
-                                               if ((b2 = data2[pix2=pix+2]) < 128)\r
-                                                       if (255 - ((255-data[pix2])<<8)/(2*b2) < 128 || b2 == 0)\r
-                                                               data2[pix2] = 0;\r
-                                                       else\r
-                                                               data2[pix2] = 255;\r
-                                               else if ((b4=2*b2-256) < 255 && (data[pix2]<<8)/(255-b4) < 128)\r
-                                                       data2[pix2] = 0;\r
-                                               else\r
-                                                       data2[pix2] = 255;\r
-                                       }\r
-                                       dataChanged = true;\r
-                                       break;\r
-                       }\r
-\r
-                       if (dataChanged) \r
-                               otherCtx.putImageData(dataDesc2,0,0);\r
-\r
-                       var ctx = params.canvas.getContext("2d");\r
-                       ctx.save();\r
-                       ctx.globalAlpha = amount;\r
-                       ctx.drawImage(\r
-                               otherCanvas,\r
-                               0,0,rect.width,rect.height,\r
-                               rect.left,rect.top,rect.width,rect.height\r
-                       );\r
-                       ctx.globalAlpha = 1;\r
-                       ctx.restore();\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}/*\r
- * Pixastic Lib - Blur filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.blur = {\r
-       process : function(params) {\r
-\r
-               if (typeof params.options.fixMargin == "undefined")\r
-                       params.options.fixMargin = true;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var dataCopy = Pixastic.prepareData(params, true)\r
-\r
-                       /*\r
-                       var kernel = [\r
-                               [0.5,   1,      0.5],\r
-                               [1,     2,      1],\r
-                               [0.5,   1,      0.5]\r
-                       ];\r
-                       */\r
-\r
-                       var kernel = [\r
-                               [0,     1,      0],\r
-                               [1,     2,      1],\r
-                               [0,     1,      0]\r
-                       ];\r
-\r
-                       var weight = 0;\r
-                       for (var i=0;i<3;i++) {\r
-                               for (var j=0;j<3;j++) {\r
-                                       weight += kernel[i][j];\r
-                               }\r
-                       }\r
-\r
-                       weight = 1 / (weight*2);\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-\r
-                               var prevY = (y == 1) ? 0 : y-2;\r
-                               var nextY = (y == h) ? y - 1 : y;\r
-\r
-                               var offsetYPrev = prevY*w*4;\r
-                               var offsetYNext = nextY*w*4;\r
-\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
-                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
-       \r
-                                       data[offset] = (\r
-                                               /*\r
-                                               dataCopy[offsetPrev - 4]\r
-                                               + dataCopy[offsetPrev+4] \r
-                                               + dataCopy[offsetNext - 4]\r
-                                               + dataCopy[offsetNext+4]\r
-                                               + \r
-                                               */\r
-                                               (dataCopy[offsetPrev]\r
-                                               + dataCopy[offset-4]\r
-                                               + dataCopy[offset+4]\r
-                                               + dataCopy[offsetNext])         * 2\r
-                                               + dataCopy[offset]              * 4\r
-                                               ) * weight;\r
-\r
-                                       data[offset+1] = (\r
-                                               /*\r
-                                               dataCopy[offsetPrev - 3]\r
-                                               + dataCopy[offsetPrev+5] \r
-                                               + dataCopy[offsetNext - 3] \r
-                                               + dataCopy[offsetNext+5]\r
-                                               + \r
-                                               */\r
-                                               (dataCopy[offsetPrev+1]\r
-                                               + dataCopy[offset-3]\r
-                                               + dataCopy[offset+5]\r
-                                               + dataCopy[offsetNext+1])       * 2\r
-                                               + dataCopy[offset+1]            * 4\r
-                                               ) * weight;\r
-\r
-                                       data[offset+2] = (\r
-                                               /*\r
-                                               dataCopy[offsetPrev - 2] \r
-                                               + dataCopy[offsetPrev+6] \r
-                                               + dataCopy[offsetNext - 2] \r
-                                               + dataCopy[offsetNext+6]\r
-                                               + \r
-                                               */\r
-                                               (dataCopy[offsetPrev+2]\r
-                                               + dataCopy[offset-2]\r
-                                               + dataCopy[offset+6]\r
-                                               + dataCopy[offsetNext+2])       * 2\r
-                                               + dataCopy[offset+2]            * 4\r
-                                               ) * weight;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=1.5)";\r
-\r
-                       if (params.options.fixMargin) {\r
-                               params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - 2 + "px";\r
-                               params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - 2 + "px";\r
-                       }\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
-       }\r
-}/*\r
- * Pixastic Lib - Blur Fast - v0.1.1\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.blurfast = {\r
-       process : function(params) {\r
-\r
-               var amount = parseFloat(params.options.amount)||0;\r
-               var clear = !!(params.options.clear && params.options.clear != "false");\r
-\r
-               amount = Math.max(0,Math.min(5,amount));\r
-\r
-               if (Pixastic.Client.hasCanvas()) {\r
-                       var rect = params.options.rect;\r
-\r
-                       var ctx = params.canvas.getContext("2d");\r
-                       ctx.save();\r
-                       ctx.beginPath();\r
-                       ctx.rect(rect.left, rect.top, rect.width, rect.height);\r
-                       ctx.clip();\r
-\r
-                       var scale = 2;\r
-                       var smallWidth = Math.round(params.width / scale);\r
-                       var smallHeight = Math.round(params.height / scale);\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = smallWidth;\r
-                       copy.height = smallHeight;\r
-\r
-                       var clear = false;\r
-                       var steps = Math.round(amount * 20);\r
-\r
-                       var copyCtx = copy.getContext("2d");\r
-                       for (var i=0;i<steps;i++) {\r
-                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));\r
-                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));\r
-       \r
-                               copyCtx.clearRect(0,0,smallWidth,smallHeight);\r
-       \r
-                               copyCtx.drawImage(\r
-                                       params.canvas,\r
-                                       0,0,params.width,params.height,\r
-                                       0,0,scaledWidth,scaledHeight\r
-                               );\r
-       \r
-                               if (clear)\r
-                                       ctx.clearRect(rect.left,rect.top,rect.width,rect.height);\r
-       \r
-                               ctx.drawImage(\r
-                                       copy,\r
-                                       0,0,scaledWidth,scaledHeight,\r
-                                       0,0,params.width,params.height\r
-                               );\r
-                       }\r
-\r
-                       ctx.restore();\r
-\r
-                       params.useData = false;\r
-                       return true;\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       var radius = 10 * amount;\r
-                       params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=" + radius + ")";\r
-\r
-                       if (params.options.fixMargin || 1) {\r
-                               params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - Math.round(radius) + "px";\r
-                               params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - Math.round(radius) + "px";\r
-                       }\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());\r
-       }\r
-}\r
-/*\r
- * Pixastic Lib - Brightness/Contrast filter - v0.1.1\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.brightness = {\r
-\r
-       process : function(params) {\r
-\r
-               var brightness = parseInt(params.options.brightness,10) || 0;\r
-               var contrast = parseFloat(params.options.contrast)||0;\r
-               var legacy = !!(params.options.legacy && params.options.legacy != "false");\r
-\r
-               if (legacy) {\r
-                       brightness = Math.min(150,Math.max(-150,brightness));\r
-               } else {\r
-                       var brightMul = 1 + Math.min(150,Math.max(-150,brightness)) / 150;\r
-               }\r
-               contrast = Math.max(0,contrast+1);\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var p = w*h;\r
-                       var pix = p*4, pix1, pix2;\r
-\r
-                       var mul, add;\r
-                       if (contrast != 1) {\r
-                               if (legacy) {\r
-                                       mul = contrast;\r
-                                       add = (brightness - 128) * contrast + 128;\r
-                               } else {\r
-                                       mul = brightMul * contrast;\r
-                                       add = - contrast * 128 + 128;\r
-                               }\r
-                       } else {  // this if-then is not necessary anymore, is it?\r
-                               if (legacy) {\r
-                                       mul = 1;\r
-                                       add = brightness;\r
-                               } else {\r
-                                       mul = brightMul;\r
-                                       add = 0;\r
-                               }\r
-                       }\r
-                       var r, g, b;\r
-                       while (p--) {\r
-                               if ((r = data[pix-=4] * mul + add) > 255 )\r
-                                       data[pix] = 255;\r
-                               else if (r < 0)\r
-                                       data[pix] = 0;\r
-                               else\r
-                                       data[pix] = r;\r
-\r
-                               if ((g = data[pix1=pix+1] * mul + add) > 255 ) \r
-                                       data[pix1] = 255;\r
-                               else if (g < 0)\r
-                                       data[pix1] = 0;\r
-                               else\r
-                                       data[pix1] = g;\r
-\r
-                               if ((b = data[pix2=pix+2] * mul + add) > 255 ) \r
-                                       data[pix2] = 255;\r
-                               else if (b < 0)\r
-                                       data[pix2] = 0;\r
-                               else\r
-                                       data[pix2] = b;\r
-                       }\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-\r
-/*\r
- * Pixastic Lib - Color adjust filter - v0.1.1\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.coloradjust = {\r
-\r
-       process : function(params) {\r
-               var red = parseFloat(params.options.red) || 0;\r
-               var green = parseFloat(params.options.green) || 0;\r
-               var blue = parseFloat(params.options.blue) || 0;\r
-\r
-               red = Math.round(red*255);\r
-               green = Math.round(green*255);\r
-               blue = Math.round(blue*255);\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var rect = params.options.rect;\r
-\r
-                       var p = rect.width*rect.height;\r
-                       var pix = p*4, pix1, pix2;\r
-\r
-                       var r, g, b;\r
-                       while (p--) {\r
-                               pix -= 4;\r
-\r
-                               if (red) {\r
-                                       if ((r = data[pix] + red) < 0 ) \r
-                                               data[pix] = 0;\r
-                                       else if (r > 255 ) \r
-                                               data[pix] = 255;\r
-                                       else\r
-                                               data[pix] = r;\r
-                               }\r
-\r
-                               if (green) {\r
-                                       if ((g = data[pix1=pix+1] + green) < 0 ) \r
-                                               data[pix1] = 0;\r
-                                       else if (g > 255 ) \r
-                                               data[pix1] = 255;\r
-                                       else\r
-                                               data[pix1] = g;\r
-                               }\r
-\r
-                               if (blue) {\r
-                                       if ((b = data[pix2=pix+2] + blue) < 0 ) \r
-                                               data[pix2] = 0;\r
-                                       else if (b > 255 ) \r
-                                               data[pix2] = 255;\r
-                                       else\r
-                                               data[pix2] = b;\r
-                               }\r
-                       }\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData());\r
-       }\r
-}\r
-/*\r
- * Pixastic Lib - Histogram - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-\r
-Pixastic.Actions.colorhistogram = {\r
-\r
-       array256 : function(default_value) {\r
-               arr = [];\r
-               for (var i=0; i<256; i++) { arr[i] = default_value; }\r
-               return arr\r
-       },\r
\r
-       process : function(params) {\r
-               var values = [];\r
-               if (typeof params.options.returnValue != "object") {\r
-                       params.options.returnValue = {rvals:[], gvals:[], bvals:[]};\r
-               }\r
-               var paint = !!(params.options.paint);\r
-\r
-               var returnValue = params.options.returnValue;\r
-               if (typeof returnValue.values != "array") {\r
-                       returnValue.rvals = [];\r
-                       returnValue.gvals = [];\r
-                       returnValue.bvals = [];\r
-               }\r
\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       params.useData = false;\r
\r
-                       var rvals = this.array256(0);\r
-                       var gvals = this.array256(0);\r
-                       var bvals = this.array256(0);\r
\r
-                       var rect = params.options.rect;\r
-\r
-                       var p = rect.width*rect.height;\r
-                       var pix = p*4;\r
-                       while (p--) {\r
-                               rvals[data[pix-=4]]++;\r
-                               gvals[data[pix+1]]++;\r
-                               bvals[data[pix+2]]++;\r
-                       }\r
\r
-                       returnValue.rvals = rvals;\r
-                       returnValue.gvals = gvals;\r
-                       returnValue.bvals = bvals;\r
-\r
-                       if (paint) {\r
-                               var ctx = params.canvas.getContext("2d");\r
-                               var vals = [rvals, gvals, bvals];\r
-                               for (var v=0;v<3;v++) {\r
-                                       var yoff = (v+1) * params.height / 3;\r
-                                       var maxValue = 0;\r
-                                       for (var i=0;i<256;i++) {\r
-                                               if (vals[v][i] > maxValue)\r
-                                                       maxValue = vals[v][i];\r
-                                       }\r
-                                       var heightScale = params.height / 3 / maxValue;\r
-                                       var widthScale = params.width / 256;\r
-                                       if (v==0) ctx.fillStyle = "rgba(255,0,0,0.5)";\r
-                                       else if (v==1) ctx.fillStyle = "rgba(0,255,0,0.5)";\r
-                                       else if (v==2) ctx.fillStyle = "rgba(0,0,255,0.5)";\r
-                                       for (var i=0;i<256;i++) {\r
-                                               ctx.fillRect(\r
-                                                       i * widthScale, params.height - heightScale * vals[v][i] - params.height + yoff,\r
-                                                       widthScale, vals[v][i] * heightScale\r
-                                               );\r
-                                       }\r
-                               }\r
-                       }\r
-                       return true;\r
-               }\r
-       },\r
-\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}/*\r
- * Pixastic Lib - Crop - v0.1.1\r
- * Copyright (c) 2008-2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.crop = {\r
-       process : function(params) {\r
-               if (Pixastic.Client.hasCanvas()) {\r
-                       var rect = params.options.rect;\r
-\r
-                       var width = rect.width;\r
-                       var height = rect.height;\r
-                       var top = rect.top;\r
-                       var left = rect.left;\r
-\r
-                       if (typeof params.options.left != "undefined")\r
-                               left = parseInt(params.options.left,10);\r
-                       if (typeof params.options.top != "undefined")\r
-                               top = parseInt(params.options.top,10);\r
-                       if (typeof params.options.height != "undefined")\r
-                               width = parseInt(params.options.width,10);\r
-                       if (typeof params.options.height != "undefined")\r
-                               height = parseInt(params.options.height,10);\r
-\r
-                       if (left < 0) left = 0;\r
-                       if (left > params.width-1) left = params.width-1;\r
-\r
-                       if (top < 0) top = 0;\r
-                       if (top > params.height-1) top = params.height-1;\r
-\r
-                       if (width < 1) width = 1;\r
-                       if (left + width > params.width)\r
-                               width = params.width - left;\r
-\r
-                       if (height < 1) height = 1;\r
-                       if (top + height > params.height)\r
-                               height = params.height - top;\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = params.width;\r
-                       copy.height = params.height;\r
-                       copy.getContext("2d").drawImage(params.canvas,0,0);\r
-\r
-                       params.canvas.width = width;\r
-                       params.canvas.height = height;\r
-                       params.canvas.getContext("2d").clearRect(0,0,width,height);\r
-\r
-                       params.canvas.getContext("2d").drawImage(copy,\r
-                               left,top,width,height,\r
-                               0,0,width,height\r
-                       );\r
-\r
-                       params.useData = false;\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvas();\r
-       }\r
-}\r
-\r
-\r
-/*\r
- * Pixastic Lib - Desaturation filter - v0.1.1\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.desaturate = {\r
-\r
-       process : function(params) {\r
-               var useAverage = !!(params.options.average && params.options.average != "false");\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var p = w*h;\r
-                       var pix = p*4, pix1, pix2;\r
-\r
-                       if (useAverage) {\r
-                               while (p--) \r
-                                       data[pix-=4] = data[pix1=pix+1] = data[pix2=pix+2] = (data[pix]+data[pix1]+data[pix2])/3\r
-                       } else {\r
-                               while (p--)\r
-                                       data[pix-=4] = data[pix1=pix+1] = data[pix2=pix+2] = (data[pix]*0.3 + data[pix1]*0.59 + data[pix2]*0.11);\r
-                       }\r
-                       return true;\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       params.image.style.filter += " gray";\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
-       }\r
-}/*\r
- * Pixastic Lib - Edge detection filter - v0.1.1\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.edges = {\r
-       process : function(params) {\r
-\r
-               var mono = !!(params.options.mono && params.options.mono != "false");\r
-               var invert = !!(params.options.invert && params.options.invert != "false");\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var dataCopy = Pixastic.prepareData(params, true)\r
-\r
-                       var c = -1/8;\r
-                       var kernel = [\r
-                               [c,     c,      c],\r
-                               [c,     1,      c],\r
-                               [c,     c,      c]\r
-                       ];\r
-\r
-                       weight = 1/c;\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-\r
-                               var nextY = (y == h) ? y - 1 : y;\r
-                               var prevY = (y == 1) ? 0 : y-2;\r
-\r
-                               var offsetYPrev = prevY*w*4;\r
-                               var offsetYNext = nextY*w*4;\r
-\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
-                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
-       \r
-                                       var r = ((dataCopy[offsetPrev-4]\r
-                                               + dataCopy[offsetPrev]\r
-                                               + dataCopy[offsetPrev+4]\r
-                                               + dataCopy[offset-4]\r
-                                               + dataCopy[offset+4]\r
-                                               + dataCopy[offsetNext-4]\r
-                                               + dataCopy[offsetNext]\r
-                                               + dataCopy[offsetNext+4]) * c\r
-                                               + dataCopy[offset]\r
-                                               ) \r
-                                               * weight;\r
-       \r
-                                       var g = ((dataCopy[offsetPrev-3]\r
-                                               + dataCopy[offsetPrev+1]\r
-                                               + dataCopy[offsetPrev+5]\r
-                                               + dataCopy[offset-3]\r
-                                               + dataCopy[offset+5]\r
-                                               + dataCopy[offsetNext-3]\r
-                                               + dataCopy[offsetNext+1]\r
-                                               + dataCopy[offsetNext+5]) * c\r
-                                               + dataCopy[offset+1])\r
-                                               * weight;\r
-       \r
-                                       var b = ((dataCopy[offsetPrev-2]\r
-                                               + dataCopy[offsetPrev+2]\r
-                                               + dataCopy[offsetPrev+6]\r
-                                               + dataCopy[offset-2]\r
-                                               + dataCopy[offset+6]\r
-                                               + dataCopy[offsetNext-2]\r
-                                               + dataCopy[offsetNext+2]\r
-                                               + dataCopy[offsetNext+6]) * c\r
-                                               + dataCopy[offset+2])\r
-                                               * weight;\r
-\r
-                                       if (mono) {\r
-                                               var brightness = (r*0.3 + g*0.59 + b*0.11)||0;\r
-                                               if (invert) brightness = 255 - brightness;\r
-                                               if (brightness < 0 ) brightness = 0;\r
-                                               if (brightness > 255 ) brightness = 255;\r
-                                               r = g = b = brightness;\r
-                                       } else {\r
-                                               if (invert) {\r
-                                                       r = 255 - r;\r
-                                                       g = 255 - g;\r
-                                                       b = 255 - b;\r
-                                               }\r
-                                               if (r < 0 ) r = 0;\r
-                                               if (g < 0 ) g = 0;\r
-                                               if (b < 0 ) b = 0;\r
-                                               if (r > 255 ) r = 255;\r
-                                               if (g > 255 ) g = 255;\r
-                                               if (b > 255 ) b = 255;\r
-                                       }\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}/*\r
- * Pixastic Lib - Edge detection 2 - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- * \r
- * Contribution by Oliver Hunt (http://nerget.com/, http://nerget.com/canvas/edgeDetection.js). Thanks Oliver!\r
- *\r
- */\r
-\r
-Pixastic.Actions.edges2 = {\r
-       process : function(params) {\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var dataCopy = Pixastic.prepareData(params, true)\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w * 4;\r
-                       var pixel = w4 + 4; // Start at (1,1)\r
-                       var hm1 = h - 1;\r
-                       var wm1 = w - 1;\r
-                       for (var y = 1; y < hm1; ++y) {\r
-                               // Prepare initial cached values for current row\r
-                               var centerRow = pixel - 4;\r
-                               var priorRow = centerRow - w4;\r
-                               var nextRow = centerRow + w4;\r
-                               \r
-                               var r1 = - dataCopy[priorRow]   - dataCopy[centerRow]   - dataCopy[nextRow];\r
-                               var g1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];\r
-                               var b1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];\r
-                               \r
-                               var rp = dataCopy[priorRow += 2];\r
-                               var gp = dataCopy[++priorRow];\r
-                               var bp = dataCopy[++priorRow];\r
-                               \r
-                               var rc = dataCopy[centerRow += 2];\r
-                               var gc = dataCopy[++centerRow];\r
-                               var bc = dataCopy[++centerRow];\r
-                               \r
-                               var rn = dataCopy[nextRow += 2];\r
-                               var gn = dataCopy[++nextRow];\r
-                               var bn = dataCopy[++nextRow];\r
-                               \r
-                               var r2 = - rp - rc - rn;\r
-                               var g2 = - gp - gc - gn;\r
-                               var b2 = - bp - bc - bn;\r
-                               \r
-                               // Main convolution loop\r
-                               for (var x = 1; x < wm1; ++x) {\r
-                                       centerRow = pixel + 4;\r
-                                       priorRow = centerRow - w4;\r
-                                       nextRow = centerRow + w4;\r
-                                       \r
-                                       var r = 127 + r1 - rp - (rc * -8) - rn;\r
-                                       var g = 127 + g1 - gp - (gc * -8) - gn;\r
-                                       var b = 127 + b1 - bp - (bc * -8) - bn;\r
-                                       \r
-                                       r1 = r2;\r
-                                       g1 = g2;\r
-                                       b1 = b2;\r
-                                       \r
-                                       rp = dataCopy[  priorRow];\r
-                                       gp = dataCopy[++priorRow];\r
-                                       bp = dataCopy[++priorRow];\r
-                                       \r
-                                       rc = dataCopy[  centerRow];\r
-                                       gc = dataCopy[++centerRow];\r
-                                       bc = dataCopy[++centerRow];\r
-                                       \r
-                                       rn = dataCopy[  nextRow];\r
-                                       gn = dataCopy[++nextRow];\r
-                                       bn = dataCopy[++nextRow];\r
-                                       \r
-                                       r += (r2 = - rp - rc - rn);\r
-                                       g += (g2 = - gp - gc - gn);\r
-                                       b += (b2 = - bp - bc - bn);\r
-\r
-                                       if (r > 255) r = 255;\r
-                                       if (g > 255) g = 255;\r
-                                       if (b > 255) b = 255;\r
-                                       if (r < 0) r = 0;\r
-                                       if (g < 0) g = 0;\r
-                                       if (b < 0) b = 0;\r
-\r
-                                       data[pixel] = r;\r
-                                       data[++pixel] = g;\r
-                                       data[++pixel] = b;\r
-                                       //data[++pixel] = 255; // alpha\r
-\r
-                                       pixel+=2;\r
-                               }\r
-                               pixel += 8;\r
-                       }\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}/*\r
- * Pixastic Lib - Emboss filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.emboss = {\r
-       process : function(params) {\r
-\r
-               var strength = parseFloat(params.options.strength)||1;\r
-               var greyLevel = typeof params.options.greyLevel != "undefined" ? parseInt(params.options.greyLevel) : 180;\r
-               var direction = params.options.direction||"topleft";\r
-               var blend = !!(params.options.blend && params.options.blend != "false");\r
-\r
-               var dirY = 0;\r
-               var dirX = 0;\r
-\r
-               switch (direction) {\r
-                       case "topleft":                 // top left\r
-                               dirY = -1;\r
-                               dirX = -1;\r
-                               break;\r
-                       case "top":                     // top\r
-                               dirY = -1;\r
-                               dirX = 0;\r
-                               break;\r
-                       case "topright":                        // top right\r
-                               dirY = -1;\r
-                               dirX = 1;\r
-                               break;\r
-                       case "right":                   // right\r
-                               dirY = 0;\r
-                               dirX = 1;\r
-                               break;\r
-                       case "bottomright":                     // bottom right\r
-                               dirY = 1;\r
-                               dirX = 1;\r
-                               break;\r
-                       case "bottom":                  // bottom\r
-                               dirY = 1;\r
-                               dirX = 0;\r
-                               break;\r
-                       case "bottomleft":                      // bottom left\r
-                               dirY = 1;\r
-                               dirX = -1;\r
-                               break;\r
-                       case "left":                    // left\r
-                               dirY = 0;\r
-                               dirX = -1;\r
-                               break;\r
-               }\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var dataCopy = Pixastic.prepareData(params, true)\r
-\r
-                       var invertAlpha = !!params.options.invertAlpha;\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-\r
-                               var otherY = dirY;\r
-                               if (y + otherY < 1) otherY = 0;\r
-                               if (y + otherY > h) otherY = 0;\r
-\r
-                               var offsetYOther = (y-1+otherY)*w*4;\r
-\r
-                               var x = w;\r
-                               do {\r
-                                               var offset = offsetY + (x-1)*4;\r
-\r
-                                               var otherX = dirX;\r
-                                               if (x + otherX < 1) otherX = 0;\r
-                                               if (x + otherX > w) otherX = 0;\r
-\r
-                                               var offsetOther = offsetYOther + (x-1+otherX)*4;\r
-\r
-                                               var dR = dataCopy[offset] - dataCopy[offsetOther];\r
-                                               var dG = dataCopy[offset+1] - dataCopy[offsetOther+1];\r
-                                               var dB = dataCopy[offset+2] - dataCopy[offsetOther+2];\r
-\r
-                                               var dif = dR;\r
-                                               var absDif = dif > 0 ? dif : -dif;\r
-\r
-                                               var absG = dG > 0 ? dG : -dG;\r
-                                               var absB = dB > 0 ? dB : -dB;\r
-\r
-                                               if (absG > absDif) {\r
-                                                       dif = dG;\r
-                                               }\r
-                                               if (absB > absDif) {\r
-                                                       dif = dB;\r
-                                               }\r
-\r
-                                               dif *= strength;\r
-\r
-                                               if (blend) {\r
-                                                       var r = data[offset] + dif;\r
-                                                       var g = data[offset+1] + dif;\r
-                                                       var b = data[offset+2] + dif;\r
-\r
-                                                       data[offset] = (r > 255) ? 255 : (r < 0 ? 0 : r);\r
-                                                       data[offset+1] = (g > 255) ? 255 : (g < 0 ? 0 : g);\r
-                                                       data[offset+2] = (b > 255) ? 255 : (b < 0 ? 0 : b);\r
-                                               } else {\r
-                                                       var grey = greyLevel - dif;\r
-                                                       if (grey < 0) {\r
-                                                               grey = 0;\r
-                                                       } else if (grey > 255) {\r
-                                                               grey = 255;\r
-                                                       }\r
-\r
-                                                       data[offset] = data[offset+1] = data[offset+2] = grey;\r
-                                               }\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-                       return true;\r
-\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       params.image.style.filter += " progid:DXImageTransform.Microsoft.emboss()";\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
-       }\r
-\r
-}\r
-/*\r
- * Pixastic Lib - Flip - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.flip = {\r
-       process : function(params) {\r
-               var rect = params.options.rect;\r
-               var copyCanvas = document.createElement("canvas");\r
-               copyCanvas.width = rect.width;\r
-               copyCanvas.height = rect.height;\r
-               copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);\r
-\r
-               var ctx = params.canvas.getContext("2d");\r
-               ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
-\r
-               if (params.options.axis == "horizontal") {\r
-                       ctx.scale(-1,1);\r
-                       ctx.drawImage(copyCanvas, -rect.left-rect.width, rect.top, rect.width, rect.height)\r
-               } else {\r
-                       ctx.scale(1,-1);\r
-                       ctx.drawImage(copyCanvas, rect.left, -rect.top-rect.height, rect.width, rect.height)\r
-               }\r
-\r
-               params.useData = false;\r
-\r
-               return true;            \r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvas();\r
-       }\r
-}\r
-\r
-/*\r
- * Pixastic Lib - Horizontal flip - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.fliph = {\r
-       process : function(params) {\r
-               if (Pixastic.Client.hasCanvas()) {\r
-                       var rect = params.options.rect;\r
-                       var copyCanvas = document.createElement("canvas");\r
-                       copyCanvas.width = rect.width;\r
-                       copyCanvas.height = rect.height;\r
-                       copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);\r
-\r
-                       var ctx = params.canvas.getContext("2d");\r
-                       ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
-                       ctx.scale(-1,1);\r
-                       ctx.drawImage(copyCanvas, -rect.left-rect.width, rect.top, rect.width, rect.height)\r
-                       params.useData = false;\r
-\r
-                       return true;            \r
-\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       params.image.style.filter += " fliph";\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());\r
-       }\r
-}\r
-\r
-/*\r
- * Pixastic Lib - Vertical flip - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.flipv = {\r
-       process : function(params) {\r
-               if (Pixastic.Client.hasCanvas()) {\r
-                       var rect = params.options.rect;\r
-                       var copyCanvas = document.createElement("canvas");\r
-                       copyCanvas.width = rect.width;\r
-                       copyCanvas.height = rect.height;\r
-                       copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);\r
-\r
-                       var ctx = params.canvas.getContext("2d");\r
-                       ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
-                       ctx.scale(1,-1);\r
-                       ctx.drawImage(copyCanvas, rect.left, -rect.top-rect.height, rect.width, rect.height)\r
-                       params.useData = false;\r
-\r
-                       return true;            \r
-\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       params.image.style.filter += " flipv";\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());\r
-       }\r
-}\r
-\r
-/*\r
- * Pixastic Lib - Glow - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-\r
-Pixastic.Actions.glow = {\r
-       process : function(params) {\r
-\r
-               var amount = (parseFloat(params.options.amount)||0);\r
-               var blurAmount = parseFloat(params.options.radius)||0;\r
-\r
-               amount = Math.min(1,Math.max(0,amount));\r
-               blurAmount = Math.min(5,Math.max(0,blurAmount));\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var rect = params.options.rect;\r
-\r
-                       var blurCanvas = document.createElement("canvas");\r
-                       blurCanvas.width = params.width;\r
-                       blurCanvas.height = params.height;\r
-                       var blurCtx = blurCanvas.getContext("2d");\r
-                       blurCtx.drawImage(params.canvas,0,0);\r
-\r
-                       var scale = 2;\r
-                       var smallWidth = Math.round(params.width / scale);\r
-                       var smallHeight = Math.round(params.height / scale);\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = smallWidth;\r
-                       copy.height = smallHeight;\r
-\r
-                       var clear = true;\r
-                       var steps = Math.round(blurAmount * 20);\r
-\r
-                       var copyCtx = copy.getContext("2d");\r
-                       for (var i=0;i<steps;i++) {\r
-                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));\r
-                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));\r
-       \r
-                               copyCtx.clearRect(0,0,smallWidth,smallHeight);\r
-       \r
-                               copyCtx.drawImage(\r
-                                       blurCanvas,\r
-                                       0,0,params.width,params.height,\r
-                                       0,0,scaledWidth,scaledHeight\r
-                               );\r
-       \r
-                               blurCtx.clearRect(0,0,params.width,params.height);\r
-       \r
-                               blurCtx.drawImage(\r
-                                       copy,\r
-                                       0,0,scaledWidth,scaledHeight,\r
-                                       0,0,params.width,params.height\r
-                               );\r
-                       }\r
-\r
-                       var data = Pixastic.prepareData(params);\r
-                       var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var r = data[offset] + amount * blurData[offset];\r
-                                       var g = data[offset+1] + amount * blurData[offset+1];\r
-                                       var b = data[offset+2] + amount * blurData[offset+2];\r
-       \r
-                                       if (r > 255) r = 255;\r
-                                       if (g > 255) g = 255;\r
-                                       if (b > 255) b = 255;\r
-                                       if (r < 0) r = 0;\r
-                                       if (g < 0) g = 0;\r
-                                       if (b < 0) b = 0;\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
- * Pixastic Lib - Histogram - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.histogram = {\r
-       process : function(params) {\r
-\r
-               var average = !!(params.options.average && params.options.average != "false");\r
-               var paint = !!(params.options.paint && params.options.paint != "false");\r
-               var color = params.options.color || "rgba(255,255,255,0.5)";\r
-               var values = [];\r
-               if (typeof params.options.returnValue != "object") {\r
-                       params.options.returnValue = {values:[]};\r
-               }\r
-               var returnValue = params.options.returnValue;\r
-               if (typeof returnValue.values != "array") {\r
-                       returnValue.values = [];\r
-               }\r
-               values = returnValue.values;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       params.useData = false;\r
-\r
-                       for (var i=0;i<256;i++) {\r
-                               values[i] = 0;\r
-                       }\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-                                       var brightness = average ? \r
-                                               Math.round((data[offset]+data[offset+1]+data[offset+2])/3)\r
-                                               : Math.round(data[offset]*0.3 + data[offset+1]*0.59 + data[offset+2]*0.11);\r
-                                       values[brightness]++;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       if (paint) {\r
-                               var maxValue = 0;\r
-                               for (var i=0;i<256;i++) {\r
-                                       if (values[i] > maxValue) {\r
-                                               maxValue = values[i];\r
-                                       }\r
-                               }\r
-                               var heightScale = params.height / maxValue;\r
-                               var widthScale = params.width / 256;\r
-                               var ctx = params.canvas.getContext("2d");\r
-                               ctx.fillStyle = color;\r
-                               for (var i=0;i<256;i++) {\r
-                                       ctx.fillRect(\r
-                                               i * widthScale, params.height - heightScale * values[i],\r
-                                               widthScale, values[i] * heightScale\r
-                                       );\r
-                               }\r
-                       }\r
-\r
-                       returnValue.values = values;\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-/*\r
- * Pixastic Lib - HSL Adjust  - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.hsl = {\r
-       process : function(params) {\r
-\r
-               var hue = parseInt(params.options.hue,10)||0;\r
-               var saturation = (parseInt(params.options.saturation,10)||0) / 100;\r
-               var lightness = (parseInt(params.options.lightness,10)||0) / 100;\r
-\r
-\r
-               // this seems to give the same result as Photoshop\r
-               if (saturation < 0) {\r
-                       var satMul = 1+saturation;\r
-               } else {\r
-                       var satMul = 1+saturation*2;\r
-               }\r
-\r
-               hue = (hue%360) / 360;\r
-               var hue6 = hue * 6;\r
-\r
-               var rgbDiv = 1 / 255;\r
-\r
-               var light255 = lightness * 255;\r
-               var lightp1 = 1 + lightness;\r
-               var lightm1 = 1 - lightness;\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var r = data[offset];\r
-                                       var g = data[offset+1];\r
-                                       var b = data[offset+2];\r
-\r
-                                       if (hue != 0 || saturation != 0) {\r
-                                               // ok, here comes rgb to hsl + adjust + hsl to rgb, all in one jumbled mess. \r
-                                               // It's not so pretty, but it's been optimized to get somewhat decent performance.\r
-                                               // The transforms were originally adapted from the ones found in Graphics Gems, but have been heavily modified.\r
-                                               var vs = r;\r
-                                               if (g > vs) vs = g;\r
-                                               if (b > vs) vs = b;\r
-                                               var ms = r;\r
-                                               if (g < ms) ms = g;\r
-                                               if (b < ms) ms = b;\r
-                                               var vm = (vs-ms);\r
-                                               var l = (ms+vs)/255 * 0.5;\r
-                                               if (l > 0) {\r
-                                                       if (vm > 0) {\r
-                                                               if (l <= 0.5) {\r
-                                                                       var s = vm / (vs+ms) * satMul;\r
-                                                                       if (s > 1) s = 1;\r
-                                                                       var v = (l * (1+s));\r
-                                                               } else {\r
-                                                                       var s = vm / (510-vs-ms) * satMul;\r
-                                                                       if (s > 1) s = 1;\r
-                                                                       var v = (l+s - l*s);\r
-                                                               }\r
-                                                               if (r == vs) {\r
-                                                                       if (g == ms)\r
-                                                                               var h = 5 + ((vs-b)/vm) + hue6;\r
-                                                                       else\r
-                                                                               var h = 1 - ((vs-g)/vm) + hue6;\r
-                                                               } else if (g == vs) {\r
-                                                                       if (b == ms)\r
-                                                                               var h = 1 + ((vs-r)/vm) + hue6;\r
-                                                                       else\r
-                                                                               var h = 3 - ((vs-b)/vm) + hue6;\r
-                                                               } else {\r
-                                                                       if (r == ms)\r
-                                                                               var h = 3 + ((vs-g)/vm) + hue6;\r
-                                                                       else\r
-                                                                               var h = 5 - ((vs-r)/vm) + hue6;\r
-                                                               }\r
-                                                               if (h < 0) h+=6;\r
-                                                               if (h >= 6) h-=6;\r
-                                                               var m = (l+l-v);\r
-                                                               var sextant = h>>0;\r
-                                                               switch (sextant) {\r
-                                                                       case 0: r = v*255; g = (m+((v-m)*(h-sextant)))*255; b = m*255; break;\r
-                                                                       case 1: r = (v-((v-m)*(h-sextant)))*255; g = v*255; b = m*255; break;\r
-                                                                       case 2: r = m*255; g = v*255; b = (m+((v-m)*(h-sextant)))*255; break;\r
-                                                                       case 3: r = m*255; g = (v-((v-m)*(h-sextant)))*255; b = v*255; break;\r
-                                                                       case 4: r = (m+((v-m)*(h-sextant)))*255; g = m*255; b = v*255; break;\r
-                                                                       case 5: r = v*255; g = m*255; b = (v-((v-m)*(h-sextant)))*255; break;\r
-                                                               }\r
-                                                       }\r
-                                               }\r
-                                       }\r
-\r
-                                       if (lightness < 0) {\r
-                                               r *= lightp1;\r
-                                               g *= lightp1;\r
-                                               b *= lightp1;\r
-                                       } else if (lightness > 0) {\r
-                                               r = r * lightm1 + light255;\r
-                                               g = g * lightm1 + light255;\r
-                                               b = b * lightm1 + light255;\r
-                                       }\r
-\r
-                                       if (r < 0) r = 0;\r
-                                       if (g < 0) g = 0;\r
-                                       if (b < 0) b = 0;\r
-                                       if (r > 255) r = 255;\r
-                                       if (g > 255) g = 255;\r
-                                       if (b > 255) b = 255;\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-\r
-}\r
-/*\r
- * Pixastic Lib - Invert filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.invert = {\r
-       process : function(params) {\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-\r
-                       var invertAlpha = !!params.options.invertAlpha;\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x-1)*4;\r
-                                       data[offset] = 255 - data[offset];\r
-                                       data[offset+1] = 255 - data[offset+1];\r
-                                       data[offset+2] = 255 - data[offset+2];\r
-                                       if (invertAlpha) data[offset+3] = 255 - data[offset+3];\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       params.image.style.filter += " invert";\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
-       }\r
-}\r
-/*\r
- * Pixastic Lib - Laplace filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.laplace = {\r
-       process : function(params) {\r
-\r
-               var strength = 1.0;\r
-               var invert = !!(params.options.invert && params.options.invert != "false");\r
-               var contrast = parseFloat(params.options.edgeStrength)||0;\r
-\r
-               var greyLevel = parseInt(params.options.greyLevel)||0;\r
-\r
-               contrast = -contrast;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var dataCopy = Pixastic.prepareData(params, true)\r
-\r
-                       var kernel = [\r
-                               [-1,    -1,     -1],\r
-                               [-1,    8,      -1],\r
-                               [-1,    -1,     -1]\r
-                       ];\r
-\r
-                       var weight = 1/8;\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-\r
-                               var nextY = (y == h) ? y - 1 : y;\r
-                               var prevY = (y == 1) ? 0 : y-2;\r
-\r
-                               var offsetYPrev = prevY*w*4;\r
-                               var offsetYNext = nextY*w*4;\r
-\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
-                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
-       \r
-                                       var r = ((-dataCopy[offsetPrev-4]\r
-                                               - dataCopy[offsetPrev]\r
-                                               - dataCopy[offsetPrev+4]\r
-                                               - dataCopy[offset-4]\r
-                                               - dataCopy[offset+4]\r
-                                               - dataCopy[offsetNext-4]\r
-                                               - dataCopy[offsetNext]\r
-                                               - dataCopy[offsetNext+4])\r
-                                               + dataCopy[offset] * 8) \r
-                                               * weight;\r
-       \r
-                                       var g = ((-dataCopy[offsetPrev-3]\r
-                                               - dataCopy[offsetPrev+1]\r
-                                               - dataCopy[offsetPrev+5]\r
-                                               - dataCopy[offset-3]\r
-                                               - dataCopy[offset+5]\r
-                                               - dataCopy[offsetNext-3]\r
-                                               - dataCopy[offsetNext+1]\r
-                                               - dataCopy[offsetNext+5])\r
-                                               + dataCopy[offset+1] * 8)\r
-                                               * weight;\r
-       \r
-                                       var b = ((-dataCopy[offsetPrev-2]\r
-                                               - dataCopy[offsetPrev+2]\r
-                                               - dataCopy[offsetPrev+6]\r
-                                               - dataCopy[offset-2]\r
-                                               - dataCopy[offset+6]\r
-                                               - dataCopy[offsetNext-2]\r
-                                               - dataCopy[offsetNext+2]\r
-                                               - dataCopy[offsetNext+6])\r
-                                               + dataCopy[offset+2] * 8)\r
-                                               * weight;\r
-\r
-                                       var brightness = ((r + g + b)/3) + greyLevel;\r
-\r
-                                       if (contrast != 0) {\r
-                                               if (brightness > 127) {\r
-                                                       brightness += ((brightness + 1) - 128) * contrast;\r
-                                               } else if (brightness < 127) {\r
-                                                       brightness -= (brightness + 1) * contrast;\r
-                                               }\r
-                                       }\r
-                                       if (invert) {\r
-                                               brightness = 255 - brightness;\r
-                                       }\r
-                                       if (brightness < 0 ) brightness = 0;\r
-                                       if (brightness > 255 ) brightness = 255;\r
-\r
-                                       data[offset] = data[offset+1] = data[offset+2] = brightness;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-\r
-/*\r
- * Pixastic Lib - Lighten filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.lighten = {\r
-\r
-       process : function(params) {\r
-               var amount = parseFloat(params.options.amount) || 0;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x-1)*4;\r
-\r
-                                       var r = data[offset];\r
-                                       var g = data[offset+1];\r
-                                       var b = data[offset+2];\r
-\r
-                                       r += r*amount;\r
-                                       g += g*amount;\r
-                                       b += b*amount;\r
-\r
-                                       if (r < 0 ) r = 0;\r
-                                       if (g < 0 ) g = 0;\r
-                                       if (b < 0 ) b = 0;\r
-                                       if (r > 255 ) r = 255;\r
-                                       if (g > 255 ) g = 255;\r
-                                       if (b > 255 ) b = 255;\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-                       return true;\r
-\r
-               } else if (Pixastic.Client.isIE()) {\r
-                       var img = params.image;\r
-                       if (amount < 0) {\r
-                               img.style.filter += " light()";\r
-                               img.filters[img.filters.length-1].addAmbient(\r
-                                       255,255,255,\r
-                                       100 * -amount\r
-                               );\r
-                       } else if (amount > 0) {\r
-                               img.style.filter += " light()";\r
-                               img.filters[img.filters.length-1].addAmbient(\r
-                                       255,255,255,\r
-                                       100\r
-                               );\r
-                               img.filters[img.filters.length-1].addAmbient(\r
-                                       255,255,255,\r
-                                       100 * amount\r
-                               );\r
-                       }\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());\r
-       }\r
-}\r
-/*\r
- * Pixastic Lib - Mosaic filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.mosaic = {\r
-\r
-       process : function(params) {\r
-               var blockSize = Math.max(1,parseInt(params.options.blockSize,10));\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-\r
-                       var ctx = params.canvas.getContext("2d");\r
-\r
-                       var pixel = document.createElement("canvas");\r
-                       pixel.width = pixel.height = 1;\r
-                       var pixelCtx = pixel.getContext("2d");\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = w;\r
-                       copy.height = h;\r
-                       var copyCtx = copy.getContext("2d");\r
-                       copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);\r
-\r
-                       for (var y=0;y<h;y+=blockSize) {\r
-                               for (var x=0;x<w;x+=blockSize) {\r
-                                       var blockSizeX = blockSize;\r
-                                       var blockSizeY = blockSize;\r
-               \r
-                                       if (blockSizeX + x > w)\r
-                                               blockSizeX = w - x;\r
-                                       if (blockSizeY + y > h)\r
-                                               blockSizeY = h - y;\r
-\r
-                                       pixelCtx.drawImage(copy, x, y, blockSizeX, blockSizeY, 0, 0, 1, 1);\r
-                                       var data = pixelCtx.getImageData(0,0,1,1).data;\r
-                                       ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";\r
-                                       ctx.fillRect(rect.left + x, rect.top + y, blockSize, blockSize);\r
-                               }\r
-                       }\r
-                       params.useData = false;\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData());\r
-       }\r
-}/*\r
- * Pixastic Lib - Noise filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.noise = {\r
-\r
-       process : function(params) {\r
-               var amount = 0;\r
-               var strength = 0;\r
-               var mono = false;\r
-\r
-               if (typeof params.options.amount != "undefined")\r
-                       amount = parseFloat(params.options.amount)||0;\r
-               if (typeof params.options.strength != "undefined")\r
-                       strength = parseFloat(params.options.strength)||0;\r
-               if (typeof params.options.mono != "undefined")\r
-                       mono = !!(params.options.mono && params.options.mono != "false");\r
-\r
-               amount = Math.max(0,Math.min(1,amount));\r
-               strength = Math.max(0,Math.min(1,strength));\r
-\r
-               var noise = 128 * strength;\r
-               var noise2 = noise / 2;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       var random = Math.random;\r
-\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x-1)*4;\r
-                                       if (random() < amount) {\r
-                                               if (mono) {\r
-                                                       var pixelNoise = - noise2 + random() * noise;\r
-                                                       var r = data[offset] + pixelNoise;\r
-                                                       var g = data[offset+1] + pixelNoise;\r
-                                                       var b = data[offset+2] + pixelNoise;\r
-                                               } else {\r
-                                                       var r = data[offset] - noise2 + (random() * noise);\r
-                                                       var g = data[offset+1] - noise2 + (random() * noise);\r
-                                                       var b = data[offset+2] - noise2 + (random() * noise);\r
-                                               }\r
-\r
-                                               if (r < 0 ) r = 0;\r
-                                               if (g < 0 ) g = 0;\r
-                                               if (b < 0 ) b = 0;\r
-                                               if (r > 255 ) r = 255;\r
-                                               if (g > 255 ) g = 255;\r
-                                               if (b > 255 ) b = 255;\r
-\r
-                                               data[offset] = r;\r
-                                               data[offset+1] = g;\r
-                                               data[offset+2] = b;\r
-                                       }\r
-                               } while (--x);\r
-                       } while (--y);\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-\r
-/*\r
- * Pixastic Lib - Posterize effect - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.posterize = {\r
-\r
-       process : function(params) {\r
-\r
-               \r
-               var numLevels = 256;\r
-               if (typeof params.options.levels != "undefined")\r
-                       numLevels = parseInt(params.options.levels,10)||1;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-\r
-                       numLevels = Math.max(2,Math.min(256,numLevels));\r
-       \r
-                       var numAreas = 256 / numLevels;\r
-                       var numValues = 256 / (numLevels-1);\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x-1)*4;\r
-\r
-                                       var r = numValues * ((data[offset] / numAreas)>>0);\r
-                                       var g = numValues * ((data[offset+1] / numAreas)>>0);\r
-                                       var b = numValues * ((data[offset+2] / numAreas)>>0);\r
-\r
-                                       if (r > 255) r = 255;\r
-                                       if (g > 255) g = 255;\r
-                                       if (b > 255) b = 255;\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-\r
-\r
-/*\r
- * Pixastic Lib - Pointillize filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.pointillize = {\r
-\r
-       process : function(params) {\r
-               var radius = Math.max(1,parseInt(params.options.radius,10));\r
-               var density = Math.min(5,Math.max(0,parseFloat(params.options.density)||0));\r
-               var noise = Math.max(0,parseFloat(params.options.noise)||0);\r
-               var transparent = !!(params.options.transparent && params.options.transparent != "false");\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-\r
-                       var ctx = params.canvas.getContext("2d");\r
-                       var canvasWidth = params.canvas.width;\r
-                       var canvasHeight = params.canvas.height;\r
-\r
-                       var pixel = document.createElement("canvas");\r
-                       pixel.width = pixel.height = 1;\r
-                       var pixelCtx = pixel.getContext("2d");\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = w;\r
-                       copy.height = h;\r
-                       var copyCtx = copy.getContext("2d");\r
-                       copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);\r
-\r
-                       var diameter = radius * 2;\r
-\r
-                       if (transparent)\r
-                               ctx.clearRect(rect.left, rect.top, rect.width, rect.height);\r
-\r
-                       var noiseRadius = radius * noise;\r
-\r
-                       var dist = 1 / density;\r
-\r
-                       for (var y=0;y<h+radius;y+=diameter*dist) {\r
-                               for (var x=0;x<w+radius;x+=diameter*dist) {\r
-                                       rndX = noise ? (x+((Math.random()*2-1) * noiseRadius))>>0 : x;\r
-                                       rndY = noise ? (y+((Math.random()*2-1) * noiseRadius))>>0 : y;\r
-\r
-                                       var pixX = rndX - radius;\r
-                                       var pixY = rndY - radius;\r
-                                       if (pixX < 0) pixX = 0;\r
-                                       if (pixY < 0) pixY = 0;\r
-\r
-                                       var cx = rndX + rect.left;\r
-                                       var cy = rndY + rect.top;\r
-                                       if (cx < 0) cx = 0;\r
-                                       if (cx > canvasWidth) cx = canvasWidth;\r
-                                       if (cy < 0) cy = 0;\r
-                                       if (cy > canvasHeight) cy = canvasHeight;\r
-\r
-                                       var diameterX = diameter;\r
-                                       var diameterY = diameter;\r
-\r
-                                       if (diameterX + pixX > w)\r
-                                               diameterX = w - pixX;\r
-                                       if (diameterY + pixY > h)\r
-                                               diameterY = h - pixY;\r
-                                       if (diameterX < 1) diameterX = 1;\r
-                                       if (diameterY < 1) diameterY = 1;\r
-\r
-                                       pixelCtx.drawImage(copy, pixX, pixY, diameterX, diameterY, 0, 0, 1, 1);\r
-                                       var data = pixelCtx.getImageData(0,0,1,1).data;\r
-\r
-                                       ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";\r
-                                       ctx.beginPath();\r
-                                       ctx.arc(cx, cy, radius, 0, Math.PI*2, true);\r
-                                       ctx.closePath();\r
-                                       ctx.fill();\r
-                               }\r
-                       }\r
-\r
-                       params.useData = false;\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData());\r
-       }\r
-}/*\r
- * Pixastic Lib - Resize - v0.1.0\r
- * Copyright (c) 2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.resize = {\r
-       process : function(params) {\r
-               if (Pixastic.Client.hasCanvas()) {\r
-                       var width = parseInt(params.options.width,10);\r
-                       var height = parseInt(params.options.height,10);\r
-                       var canvas = params.canvas;\r
-\r
-                       if (width < 1) width = 1;\r
-                       if (width < 2) width = 2;\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = width;\r
-                       copy.height = height;\r
-\r
-                       copy.getContext("2d").drawImage(canvas,0,0,width,height);\r
-                       canvas.width = width;\r
-                       canvas.height = height;\r
-\r
-                       canvas.getContext("2d").drawImage(copy,0,0);\r
-\r
-                       params.useData = false;\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvas();\r
-       }\r
-}\r
-\r
-\r
-/*\r
- * Pixastic Lib - Remove noise - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.removenoise = {\r
-       process : function(params) {\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-\r
-                               var nextY = (y == h) ? y - 1 : y;\r
-                               var prevY = (y == 1) ? 0 : y-2;\r
-\r
-                               var offsetYPrev = prevY*w*4;\r
-                               var offsetYNext = nextY*w*4;\r
-\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
-                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
-\r
-                                       var minR, maxR, minG, maxG, minB, maxB;\r
-\r
-                                       minR = maxR = data[offsetPrev];\r
-                                       var r1 = data[offset-4], r2 = data[offset+4], r3 = data[offsetNext];\r
-                                       if (r1 < minR) minR = r1;\r
-                                       if (r2 < minR) minR = r2;\r
-                                       if (r3 < minR) minR = r3;\r
-                                       if (r1 > maxR) maxR = r1;\r
-                                       if (r2 > maxR) maxR = r2;\r
-                                       if (r3 > maxR) maxR = r3;\r
-\r
-                                       minG = maxG = data[offsetPrev+1];\r
-                                       var g1 = data[offset-3], g2 = data[offset+5], g3 = data[offsetNext+1];\r
-                                       if (g1 < minG) minG = g1;\r
-                                       if (g2 < minG) minG = g2;\r
-                                       if (g3 < minG) minG = g3;\r
-                                       if (g1 > maxG) maxG = g1;\r
-                                       if (g2 > maxG) maxG = g2;\r
-                                       if (g3 > maxG) maxG = g3;\r
-\r
-                                       minB = maxB = data[offsetPrev+2];\r
-                                       var b1 = data[offset-2], b2 = data[offset+6], b3 = data[offsetNext+2];\r
-                                       if (b1 < minB) minB = b1;\r
-                                       if (b2 < minB) minB = b2;\r
-                                       if (b3 < minB) minB = b3;\r
-                                       if (b1 > maxB) maxB = b1;\r
-                                       if (b2 > maxB) maxB = b2;\r
-                                       if (b3 > maxB) maxB = b3;\r
-\r
-                                       if (data[offset] > maxR) {\r
-                                               data[offset] = maxR;\r
-                                       } else if (data[offset] < minR) {\r
-                                               data[offset] = minR;\r
-                                       }\r
-                                       if (data[offset+1] > maxG) {\r
-                                               data[offset+1] = maxG;\r
-                                       } else if (data[offset+1] < minG) {\r
-                                               data[offset+1] = minG;\r
-                                       }\r
-                                       if (data[offset+2] > maxB) {\r
-                                               data[offset+2] = maxB;\r
-                                       } else if (data[offset+2] < minB) {\r
-                                               data[offset+2] = minB;\r
-                                       }\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}/*\r
- * Pixastic Lib - Rotate - v0.1.0\r
- * Copyright (c) 2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.rotate = {\r
-       process : function(params) {\r
-               if (Pixastic.Client.hasCanvas()) {\r
-                       var canvas = params.canvas;\r
-\r
-                       var width = params.width;\r
-                       var height = params.height;\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = width;\r
-                       copy.height = height;\r
-                       copy.getContext("2d").drawImage(canvas,0,0,width,height);\r
-\r
-                       var angle = -parseFloat(params.options.angle) * Math.PI / 180;\r
-\r
-                       var dimAngle = angle;\r
-                       if (dimAngle > Math.PI*0.5)\r
-                               dimAngle = Math.PI - dimAngle;\r
-                       if (dimAngle < -Math.PI*0.5)\r
-                               dimAngle = -Math.PI - dimAngle;\r
-\r
-                       var diag = Math.sqrt(width*width + height*height);\r
-\r
-                       var diagAngle1 = Math.abs(dimAngle) - Math.abs(Math.atan2(height, width));\r
-                       var diagAngle2 = Math.abs(dimAngle) + Math.abs(Math.atan2(height, width));\r
-\r
-                       var newWidth = Math.abs(Math.cos(diagAngle1) * diag);\r
-                       var newHeight = Math.abs(Math.sin(diagAngle2) * diag);\r
-\r
-                       canvas.width = newWidth;\r
-                       canvas.height = newHeight;\r
-\r
-                       var ctx = canvas.getContext("2d");\r
-                       ctx.translate(newWidth/2, newHeight/2);\r
-                       ctx.rotate(angle);\r
-                       ctx.drawImage(copy,-width/2,-height/2);\r
-\r
-                       params.useData = false;\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvas();\r
-       }\r
-}\r
-\r
-\r
-/*\r
- * Pixastic Lib - Sepia filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.sepia = {\r
-\r
-       process : function(params) {\r
-               var mode = (parseInt(params.options.mode,10)||0);\r
-               if (mode < 0) mode = 0;\r
-               if (mode > 1) mode = 1;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x-1)*4;\r
-\r
-                                       if (mode) {\r
-                                               // a bit faster, but not as good\r
-                                               var d = data[offset] * 0.299 + data[offset+1] * 0.587 + data[offset+2] * 0.114;\r
-                                               var r = (d + 39);\r
-                                               var g = (d + 14);\r
-                                               var b = (d - 36);\r
-                                       } else {\r
-                                               // Microsoft\r
-                                               var or = data[offset];\r
-                                               var og = data[offset+1];\r
-                                               var ob = data[offset+2];\r
-       \r
-                                               var r = (or * 0.393 + og * 0.769 + ob * 0.189);\r
-                                               var g = (or * 0.349 + og * 0.686 + ob * 0.168);\r
-                                               var b = (or * 0.272 + og * 0.534 + ob * 0.131);\r
-                                       }\r
-\r
-                                       if (r < 0) r = 0; if (r > 255) r = 255;\r
-                                       if (g < 0) g = 0; if (g > 255) g = 255;\r
-                                       if (b < 0) b = 0; if (b > 255) b = 255;\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}/*\r
- * Pixastic Lib - Sharpen filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.sharpen = {\r
-       process : function(params) {\r
-\r
-               var strength = 0;\r
-               if (typeof params.options.amount != "undefined")\r
-                       strength = parseFloat(params.options.amount)||0;\r
-\r
-               if (strength < 0) strength = 0;\r
-               if (strength > 1) strength = 1;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var dataCopy = Pixastic.prepareData(params, true)\r
-\r
-                       var mul = 15;\r
-                       var mulOther = 1 + 3*strength;\r
-\r
-                       var kernel = [\r
-                               [0,     -mulOther,      0],\r
-                               [-mulOther,     mul,    -mulOther],\r
-                               [0,     -mulOther,      0]\r
-                       ];\r
-\r
-                       var weight = 0;\r
-                       for (var i=0;i<3;i++) {\r
-                               for (var j=0;j<3;j++) {\r
-                                       weight += kernel[i][j];\r
-                               }\r
-                       }\r
-\r
-                       weight = 1 / weight;\r
-\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-\r
-                       mul *= weight;\r
-                       mulOther *= weight;\r
-\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-\r
-                               var nextY = (y == h) ? y - 1 : y;\r
-                               var prevY = (y == 1) ? 0 : y-2;\r
-\r
-                               var offsetYPrev = prevY*w4;\r
-                               var offsetYNext = nextY*w4;\r
-\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;\r
-                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;\r
-\r
-                                       var r = ((\r
-                                               - dataCopy[offsetPrev]\r
-                                               - dataCopy[offset-4]\r
-                                               - dataCopy[offset+4]\r
-                                               - dataCopy[offsetNext])         * mulOther\r
-                                               + dataCopy[offset]      * mul\r
-                                               );\r
-\r
-                                       var g = ((\r
-                                               - dataCopy[offsetPrev+1]\r
-                                               - dataCopy[offset-3]\r
-                                               - dataCopy[offset+5]\r
-                                               - dataCopy[offsetNext+1])       * mulOther\r
-                                               + dataCopy[offset+1]    * mul\r
-                                               );\r
-\r
-                                       var b = ((\r
-                                               - dataCopy[offsetPrev+2]\r
-                                               - dataCopy[offset-2]\r
-                                               - dataCopy[offset+6]\r
-                                               - dataCopy[offsetNext+2])       * mulOther\r
-                                               + dataCopy[offset+2]    * mul\r
-                                               );\r
-\r
-\r
-                                       if (r < 0 ) r = 0;\r
-                                       if (g < 0 ) g = 0;\r
-                                       if (b < 0 ) b = 0;\r
-                                       if (r > 255 ) r = 255;\r
-                                       if (g > 255 ) g = 255;\r
-                                       if (b > 255 ) b = 255;\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-/*\r
- * Pixastic Lib - Solarize filter - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-Pixastic.Actions.solarize = {\r
-\r
-       process : function(params) {\r
-               var useAverage = !!(params.options.average && params.options.average != "false");\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var data = Pixastic.prepareData(params);\r
-                       var rect = params.options.rect;\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x-1)*4;\r
-\r
-                                       var r = data[offset];\r
-                                       var g = data[offset+1];\r
-                                       var b = data[offset+2];\r
-\r
-                                       if (r > 127) r = 255 - r;\r
-                                       if (g > 127) g = 255 - g;\r
-                                       if (b > 127) b = 255 - b;\r
-\r
-                                       data[offset] = r;\r
-                                       data[offset+1] = g;\r
-                                       data[offset+2] = b;\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return (Pixastic.Client.hasCanvasImageData());\r
-       }\r
-}/*\r
- * Pixastic Lib - USM - v0.1.0\r
- * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/\r
- * License: [http://www.pixastic.com/lib/license.txt]\r
- */\r
-\r
-\r
-Pixastic.Actions.unsharpmask = {\r
-       process : function(params) {\r
-\r
-               var amount = (parseFloat(params.options.amount)||0);\r
-               var blurAmount = parseFloat(params.options.radius)||0;\r
-               var threshold = parseFloat(params.options.threshold)||0;\r
-\r
-               amount = Math.min(500,Math.max(0,amount)) / 2;\r
-               blurAmount = Math.min(5,Math.max(0,blurAmount)) / 10;\r
-               threshold = Math.min(255,Math.max(0,threshold));\r
-\r
-               threshold--;\r
-               var thresholdNeg = -threshold;\r
-\r
-               amount *= 0.016;\r
-               amount++;\r
-\r
-               if (Pixastic.Client.hasCanvasImageData()) {\r
-                       var rect = params.options.rect;\r
-\r
-                       var blurCanvas = document.createElement("canvas");\r
-                       blurCanvas.width = params.width;\r
-                       blurCanvas.height = params.height;\r
-                       var blurCtx = blurCanvas.getContext("2d");\r
-                       blurCtx.drawImage(params.canvas,0,0);\r
-\r
-                       var scale = 2;\r
-                       var smallWidth = Math.round(params.width / scale);\r
-                       var smallHeight = Math.round(params.height / scale);\r
-\r
-                       var copy = document.createElement("canvas");\r
-                       copy.width = smallWidth;\r
-                       copy.height = smallHeight;\r
-\r
-                       var steps = Math.round(blurAmount * 20);\r
-\r
-                       var copyCtx = copy.getContext("2d");\r
-                       for (var i=0;i<steps;i++) {\r
-                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));\r
-                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));\r
-\r
-                               copyCtx.clearRect(0,0,smallWidth,smallHeight);\r
-\r
-                               copyCtx.drawImage(\r
-                                       blurCanvas,\r
-                                       0,0,params.width,params.height,\r
-                                       0,0,scaledWidth,scaledHeight\r
-                               );\r
-       \r
-                               blurCtx.clearRect(0,0,params.width,params.height);\r
-       \r
-                               blurCtx.drawImage(\r
-                                       copy,\r
-                                       0,0,scaledWidth,scaledHeight,\r
-                                       0,0,params.width,params.height\r
-                               );\r
-                       }\r
-\r
-                       var data = Pixastic.prepareData(params);\r
-                       var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});\r
-                       var w = rect.width;\r
-                       var h = rect.height;\r
-                       var w4 = w*4;\r
-                       var y = h;\r
-                       do {\r
-                               var offsetY = (y-1)*w4;\r
-                               var x = w;\r
-                               do {\r
-                                       var offset = offsetY + (x*4-4);\r
-\r
-                                       var difR = data[offset] - blurData[offset];\r
-                                       if (difR > threshold || difR < thresholdNeg) {\r
-                                               var blurR = blurData[offset];\r
-                                               blurR = amount * difR + blurR;\r
-                                               data[offset] = blurR > 255 ? 255 : (blurR < 0 ? 0 : blurR);\r
-                                       }\r
-\r
-                                       var difG = data[offset+1] - blurData[offset+1];\r
-                                       if (difG > threshold || difG < thresholdNeg) {\r
-                                               var blurG = blurData[offset+1];\r
-                                               blurG = amount * difG + blurG;\r
-                                               data[offset+1] = blurG > 255 ? 255 : (blurG < 0 ? 0 : blurG);\r
-                                       }\r
-\r
-                                       var difB = data[offset+2] - blurData[offset+2];\r
-                                       if (difB > threshold || difB < thresholdNeg) {\r
-                                               var blurB = blurData[offset+2];\r
-                                               blurB = amount * difB + blurB;\r
-                                               data[offset+2] = blurB > 255 ? 255 : (blurB < 0 ? 0 : blurB);\r
-                                       }\r
-\r
-                               } while (--x);\r
-                       } while (--y);\r
-\r
-                       return true;\r
-               }\r
-       },\r
-       checkSupport : function() {\r
-               return Pixastic.Client.hasCanvasImageData();\r
-       }\r
-}\r
-\r
-\r
-\r
-\r
+/*
+ * Pixastic Lib - Core Functions - v0.1.3
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+var Pixastic = (function() {
+
+
+       function addEvent(el, event, handler) {
+               if (el.addEventListener)
+                       el.addEventListener(event, handler, false); 
+               else if (el.attachEvent)
+                       el.attachEvent("on" + event, handler); 
+       }
+
+       function onready(handler) {
+               var handlerDone = false;
+               var execHandler = function() {
+                       if (!handlerDone) {
+                               handlerDone = true;
+                               handler();
+                       }
+               }
+               document.write("<"+"script defer src=\"//:\" id=\"__onload_ie_sumbox__\"></"+"script>");
+               var script = document.getElementById("__onload_ie_sumbox__");
+               script.onreadystatechange = function() {
+                       if (script.readyState == "complete") {
+                               script.parentNode.removeChild(script);
+                               execHandler();
+                       }
+               }
+               if (document.addEventListener)
+                       document.addEventListener("DOMContentLoaded", execHandler, false); 
+               addEvent(window, "load", execHandler);
+       }
+
+       function init() {
+               if (!Pixastic.parseOnLoad) return;
+               var imgEls = getElementsByClass("pixastic", null, "img");
+               var canvasEls = getElementsByClass("pixastic", null, "canvas");
+               var elements = imgEls.concat(canvasEls);
+               for (var i=0;i<elements.length;i++) {
+                       (function() {
+
+                       var el = elements[i];
+                       var actions = [];
+                       var classes = el.className.split(" ");
+                       for (var c=0;c<classes.length;c++) {
+                               var cls = classes[c];
+                               if (cls.substring(0,9) == "pixastic-") {
+                                       var actionName = cls.substring(9);
+                                       if (actionName != "")
+                                               actions.push(actionName);
+                               }
+                       }
+                       if (actions.length) {
+                               if (el.tagName.toLowerCase() == "img") {
+                                       var dataImg = new Image();
+                                       dataImg.src = el.src;
+                                       if (dataImg.complete) {
+                                               for (var a=0;a<actions.length;a++) {
+                                                       var res = Pixastic.applyAction(el, el, actions[a], null);
+                                                       if (res) 
+                                                               el = res;
+                                               }
+                                       } else {
+                                               dataImg.onload = function() {
+                                                       for (var a=0;a<actions.length;a++) {
+                                                               var res = Pixastic.applyAction(el, el, actions[a], null)
+                                                               if (res) 
+                                                                       el = res;
+                                                       }
+                                               }
+                                       }
+                               } else {
+                                       setTimeout(function() {
+                                               for (var a=0;a<actions.length;a++) {
+                                                       var res = Pixastic.applyAction(
+                                                               el, el, actions[a], null
+                                                       );
+                                                       if (res) 
+                                                               el = res;
+                                               }
+                                       },1);
+                               }
+                       }
+
+                       })();
+               }
+       }
+
+//     if (typeof pixastic_no_onready == "undefined") // yuck.
+//             onready(init);
+
+       // getElementsByClass by Dustin Diaz, http://www.dustindiaz.com/getelementsbyclass/
+       function getElementsByClass(searchClass,node,tag) {
+               var classElements = new Array();
+               if ( node == null )
+                       node = document;
+               if ( tag == null )
+                       tag = '*';
+
+               var els = node.getElementsByTagName(tag);
+               var elsLen = els.length;
+               var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
+               for (i = 0, j = 0; i < elsLen; i++) {
+                       if ( pattern.test(els[i].className) ) {
+                               classElements[j] = els[i];
+                               j++;
+                       }
+               }
+               return classElements;
+       }
+
+       var debugElement;
+
+       function writeDebug(text, level) {
+               if (!Pixastic.debug) return;
+               try {
+                       switch (level) {
+                               case "warn" : 
+                                       console.warn("Pixastic:", text);
+                                       break;
+                               case "error" :
+                                       console.error("Pixastic:", text);
+                                       break;
+                               default:
+                                       console.log("Pixastic:", text);
+                       }
+               } catch(e) {
+               }
+               if (!debugElement) {
+                       
+               }
+       }
+
+
+       return {
+
+               parseOnLoad : false,
+
+               debug : false,
+               
+               applyAction : function(img, dataImg, actionName, options) {
+
+                       options = options || {};
+
+                       var imageIsCanvas = (img.tagName.toLowerCase() == "canvas");
+                       if (imageIsCanvas && Pixastic.Client.isIE()) {
+                               if (Pixastic.debug) writeDebug("Tried to process a canvas element but browser is IE.");
+                               return false;
+                       }
+
+                       var canvas, ctx;
+                       if (Pixastic.Client.hasCanvas()) {
+                               canvas = document.createElement("canvas");
+                               ctx = canvas.getContext("2d");
+                       }
+
+                       var w = parseInt(img.offsetWidth);
+                       var h = parseInt(img.offsetHeight);
+
+                       if (imageIsCanvas) {
+                               w = img.width;
+                               h = img.height;
+                       }
+
+                       if (actionName.indexOf("(") > -1) {
+                               var tmp = actionName;
+                               actionName = tmp.substr(0, tmp.indexOf("("));
+                               var arg = tmp.match(/\((.*?)\)/);
+                               if (arg[1]) {
+                                       arg = arg[1].split(";");
+                                       for (var a=0;a<arg.length;a++) {
+                                               thisArg = arg[a].split("=");
+                                               if (thisArg.length == 2) {
+                                                       if (thisArg[0] == "rect") {
+                                                               var rectVal = thisArg[1].split(",");
+                                                               options[thisArg[0]] = {
+                                                                       left : parseInt(rectVal[0],10)||0,
+                                                                       top : parseInt(rectVal[1],10)||0,
+                                                                       width : parseInt(rectVal[2],10)||0,
+                                                                       height : parseInt(rectVal[3],10)||0
+                                                               }
+                                                       } else {
+                                                               options[thisArg[0]] = thisArg[1];
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (!options.rect) {
+                               options.rect = {
+                                       left : 0, top : 0, width : w, height : h
+                               };
+                       }
+                       var validAction = false;
+                       if (Pixastic.Actions[actionName] && typeof Pixastic.Actions[actionName].process == "function") {
+                               validAction = true;
+                       }
+                       if (!validAction) {
+                               if (Pixastic.debug) writeDebug("Invalid action \"" + actionName + "\". Maybe file not included?");
+                               return false;
+                       }
+                       if (!Pixastic.Actions[actionName].checkSupport()) {
+                               if (Pixastic.debug) writeDebug("Action \"" + actionName + "\" not supported by this browser.");
+                               return false;
+                       }
+
+                       if (Pixastic.Client.hasCanvas()) {
+                               canvas.width = w;
+                               canvas.height = h;
+                               canvas.style.width = w+"px";
+                               canvas.style.height = h+"px";
+                               ctx.drawImage(dataImg,0,0,w,h);
+
+                               if (!img.__pixastic_org_image) {
+                                       canvas.__pixastic_org_image = img;
+                                       canvas.__pixastic_org_width = w;
+                                       canvas.__pixastic_org_height = h;
+                               } else {
+                                       canvas.__pixastic_org_image = img.__pixastic_org_image;
+                                       canvas.__pixastic_org_width = img.__pixastic_org_width;
+                                       canvas.__pixastic_org_height = img.__pixastic_org_height;
+                               }
+
+                       } else if (Pixastic.Client.isIE() && typeof img.__pixastic_org_style == "undefined") {
+                               img.__pixastic_org_style = img.style.cssText;
+                       }
+
+                       var params = {
+                               image : img,
+                               canvas : canvas,
+                               width : w,
+                               height : h,
+                               useData : true,
+                               options : options
+                       }
+
+                       // Ok, let's do it!
+
+                       var res = Pixastic.Actions[actionName].process(params);
+
+                       if (!res) {
+                               return false;
+                       }
+
+                       if (Pixastic.Client.hasCanvas()) {
+                               if (params.useData) {
+                                       if (Pixastic.Client.hasCanvasImageData()) {
+                                               canvas.getContext("2d").putImageData(params.canvasData, options.rect.left, options.rect.top);
+
+                                               // Opera doesn't seem to update the canvas until we draw something on it, lets draw a 0x0 rectangle.
+                                               canvas.getContext("2d").fillRect(0,0,0,0);
+                                       }
+                               }
+
+                               if (!options.leaveDOM) {
+                                       // copy properties and stuff from the source image
+                                       canvas.title = img.title;
+                                       canvas.imgsrc = img.imgsrc;
+                                       if (!imageIsCanvas) canvas.alt  = img.alt;
+                                       if (!imageIsCanvas) canvas.imgsrc = img.src;
+                                       canvas.className = img.className;
+                                       canvas.style.cssText = img.style.cssText;
+                                       canvas.name = img.name;
+                                       canvas.tabIndex = img.tabIndex;
+                                       canvas.id = img.id;
+                                       if (img.parentNode && img.parentNode.replaceChild) {
+                                               img.parentNode.replaceChild(canvas, img);
+                                       }
+                               }
+
+                               options.resultCanvas = canvas;
+
+                               return canvas;
+                       }
+
+                       return img;
+               },
+
+               prepareData : function(params, getCopy) {
+                       var ctx = params.canvas.getContext("2d");
+                       var rect = params.options.rect;
+                       var dataDesc = ctx.getImageData(rect.left, rect.top, rect.width, rect.height);
+                       var data = dataDesc.data;
+                       if (!getCopy) params.canvasData = dataDesc;
+                       return data;
+               },
+
+               // load the image file
+               process : function(img, actionName, options, callback)
+               {
+                       if (img.tagName.toLowerCase() == "img") {
+                               var dataImg = new Image();
+                               dataImg.src = img.src;
+                               if (dataImg.complete) {
+                                       var res = Pixastic.applyAction(img, dataImg, actionName, options);
+                                       if (callback) callback(res);
+                                       return res;
+                               } else {
+                                       dataImg.onload = function() {
+                                               var res = Pixastic.applyAction(img, dataImg, actionName, options)
+                                               if (callback) callback(res);
+                                       }
+                               }
+                       }
+                       if (img.tagName.toLowerCase() == "canvas") {
+                               var res = Pixastic.applyAction(img, img, actionName, options);
+                               if (callback) callback(res);
+                               return res;
+                       }
+               },
+
+               revert : function(img) {
+                       if (Pixastic.Client.hasCanvas()) {
+                               if (img.tagName.toLowerCase() == "canvas" && img.__pixastic_org_image) {
+                                       img.width = img.__pixastic_org_width;
+                                       img.height = img.__pixastic_org_height;
+                                       img.getContext("2d").drawImage(img.__pixastic_org_image, 0, 0);
+
+                                       if (img.parentNode && img.parentNode.replaceChild) {
+                                               img.parentNode.replaceChild(img.__pixastic_org_image, img);
+                                       }
+
+                                       return img;
+                               }
+                       } else if (Pixastic.Client.isIE() && typeof img.__pixastic_org_style != "undefined") {
+                               img.style.cssText = img.__pixastic_org_style;
+                       }
+               },
+
+               Client : {
+                       hasCanvas : (function() {
+                               var c = document.createElement("canvas");
+                               var val = false;
+                               try {
+                                       val = !!((typeof c.getContext == "function") && c.getContext("2d"));
+                               } catch(e) {}
+                               return function() {
+                                       return val;
+                               }
+                       })(),
+
+                       hasCanvasImageData : (function() {
+                               var c = document.createElement("canvas");
+                               var val = false;
+                               var ctx;
+                               try {
+                                       if (typeof c.getContext == "function" && (ctx = c.getContext("2d"))) {
+                                               val = (typeof ctx.getImageData == "function");
+                                       }
+                               } catch(e) {}
+                               return function() {
+                                       return val;
+                               }
+                       })(),
+
+                       isIE : function() {
+                               return !!document.all && !!window.attachEvent && !window.opera;
+                       }
+               },
+
+               Actions : {}
+       }
+
+
+})();
+/*
+ * Pixastic Lib - jQuery plugin
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+if (typeof jQuery != "undefined" && jQuery && jQuery.fn) {
+       jQuery.fn.pixastic = function(action, options) {
+               var newElements = [];
+               this.each(
+                       function () {
+                               if (this.tagName.toLowerCase() == "img" && !this.complete) {
+                                       return;
+                               }
+                               var res = Pixastic.process(this, action, options);
+                               if (res) {
+                                       newElements.push(res);
+                               }
+                       }
+               );
+               if (newElements.length > 0)
+                       return jQuery(newElements);
+               else
+                       return this;
+       };
+
+};
+/*
+ * Pixastic Lib - Blend - v0.1.1
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.blend = {
+
+       process : function(params) {
+               var amount = parseFloat(params.options.amount);
+               var mode = (params.options.mode || "normal").toLowerCase();
+               var image = params.options.image;
+
+               amount = Math.max(0,Math.min(1,amount));
+
+               if (!image) return false;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var rect = params.options.rect;
+                       var data = Pixastic.prepareData(params);
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       params.useData = false;
+
+                       var otherCanvas = document.createElement("canvas");
+                       otherCanvas.width = params.canvas.width;
+                       otherCanvas.height = params.canvas.height;
+                       var otherCtx = otherCanvas.getContext("2d");
+                       otherCtx.drawImage(image,0,0);
+
+                       var params2 = {canvas:otherCanvas,options:params.options};
+                       var data2 = Pixastic.prepareData(params2);
+                       var dataDesc2 = params2.canvasData;
+
+                       var p = w*h;
+                       var pix = p*4;
+                       var pix1, pix2;
+                       var r1, g1, b1;
+                       var r2, g2, b2;
+                       var r3, g3, b3;
+                       var r4, g4, b4;
+
+                       var dataChanged = false;
+
+                       switch (mode) {
+                               case "normal" : 
+                                       //while (p--) {
+                                       //      data2[pix-=4] = data2[pix];
+                                       //      data2[pix1=pix+1] = data2[pix1];
+                                       //      data2[pix2=pix+2] = data2[pix2];
+                                       //}
+                                       break;
+
+                               case "multiply" : 
+                                       while (p--) {
+                                               data2[pix-=4] = data[pix] * data2[pix] / 255;
+                                               data2[pix1=pix+1] = data[pix1] * data2[pix1] / 255;
+                                               data2[pix2=pix+2] = data[pix2] * data2[pix2] / 255;
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "lighten" : 
+                                       while (p--) {
+                                               if ((r1 = data[pix-=4]) > data2[pix])
+                                                       data2[pix] = r1;
+                                               if ((g1 = data[pix1=pix+1]) > data2[pix1])
+                                                       data2[pix1] = g1;
+                                               if ((b1 = data[pix2=pix+2]) > data2[pix2])
+                                                       data2[pix2] = b1;
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "darken" : 
+                                       while (p--) {
+                                               if ((r1 = data[pix-=4]) < data2[pix])
+                                                       data2[pix] = r1;
+                                               if ((g1 = data[pix1=pix+1]) < data2[pix1])
+                                                       data2[pix1] = g1;
+                                               if ((b1 = data[pix2=pix+2]) < data2[pix2])
+                                                       data2[pix2] = b1;
+
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "darkercolor" : 
+                                       while (p--) {
+                                               if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) <= (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {
+                                                       data2[pix] = r1;
+                                                       data2[pix1] = g1;
+                                                       data2[pix2] = b1;
+                                               }
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "lightercolor" : 
+                                       while (p--) {
+                                               if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) > (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {
+                                                       data2[pix] = r1;
+                                                       data2[pix1] = g1;
+                                                       data2[pix2] = b1;
+                                               }
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "lineardodge" : 
+                                       otherCtx.globalCompositeOperation = "source-over";
+                                       otherCtx.drawImage(params.canvas, 0, 0);
+                                       otherCtx.globalCompositeOperation = "lighter";
+                                       otherCtx.drawImage(image, 0, 0);
+
+                                       /*
+                                       while (p--) {
+                                               if ((r3 = data[pix-=4] + data2[pix]) > 255)
+                                                       data2[pix] = 255;
+                                               else
+                                                       data2[pix] = r3;
+                                               if ((g3 = data[pix1=pix+1] + data2[pix1]) > 255)
+                                                       data2[pix1] = 255;
+                                               else
+                                                       data2[pix1] = g3;
+                                               if ((b3 = data[pix2=pix+2] + data2[pix2]) > 255)
+                                                       data2[pix2] = 255;
+                                               else
+                                                       data2[pix2] = b3;
+                                       }
+                                       dataChanged = true;
+                                       */
+
+                                       break;
+
+                               case "linearburn" : 
+                                       while (p--) {
+                                               if ((r3 = data[pix-=4] + data2[pix]) < 255)
+                                                       data2[pix] = 0;
+                                               else
+                                                       data2[pix] = (r3 - 255);
+                                               if ((g3 = data[pix1=pix+1] + data2[pix1]) < 255)
+                                                       data2[pix1] = 0;
+                                               else
+                                                       data2[pix1] = (g3 - 255);
+                                               if ((b3 = data[pix2=pix+2] + data2[pix2]) < 255)
+                                                       data2[pix2] = 0;
+                                               else
+                                                       data2[pix2] = (b3 - 255);
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "difference" : 
+                                       while (p--) {
+                                               if ((r3 = data[pix-=4] - data2[pix]) < 0)
+                                                       data2[pix] = -r3;
+                                               else
+                                                       data2[pix] = r3;
+                                               if ((g3 = data[pix1=pix+1] - data2[pix1]) < 0)
+                                                       data2[pix1] = -g3;
+                                               else
+                                                       data2[pix1] = g3;
+                                               if ((b3 = data[pix2=pix+2] - data2[pix2]) < 0)
+                                                       data2[pix2] = -b3;
+                                               else
+                                                       data2[pix2] = b3;
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "screen" : 
+                                       while (p--) {
+                                               data2[pix-=4] = (255 - ( ((255-data2[pix])*(255-data[pix])) >> 8));
+                                               data2[pix1=pix+1] = (255 - ( ((255-data2[pix1])*(255-data[pix1])) >> 8));
+                                               data2[pix2=pix+2] = (255 - ( ((255-data2[pix2])*(255-data[pix2])) >> 8));
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "exclusion" : 
+                                       var div_2_255 = 2 / 255;
+                                       while (p--) {
+                                               data2[pix-=4] = (r1 = data[pix]) - (r1 * div_2_255 - 1) * data2[pix];
+                                               data2[pix1=pix+1] = (g1 = data[pix1]) - (g1 * div_2_255 - 1) * data2[pix1];
+                                               data2[pix2=pix+2] = (b1 = data[pix2]) - (b1 * div_2_255 - 1) * data2[pix2];
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "overlay" : 
+                                       var div_2_255 = 2 / 255;
+                                       while (p--) {
+                                               if ((r1 = data[pix-=4]) < 128)
+                                                       data2[pix] = data2[pix]*r1*div_2_255;
+                                               else
+                                                       data2[pix] = 255 - (255-data2[pix])*(255-r1)*div_2_255;
+
+                                               if ((g1 = data[pix1=pix+1]) < 128)
+                                                       data2[pix1] = data2[pix1]*g1*div_2_255;
+                                               else
+                                                       data2[pix1] = 255 - (255-data2[pix1])*(255-g1)*div_2_255;
+
+                                               if ((b1 = data[pix2=pix+2]) < 128)
+                                                       data2[pix2] = data2[pix2]*b1*div_2_255;
+                                               else
+                                                       data2[pix2] = 255 - (255-data2[pix2])*(255-b1)*div_2_255;
+
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "softlight" : 
+                                       var div_2_255 = 2 / 255;
+                                       while (p--) {
+                                               if ((r1 = data[pix-=4]) < 128)
+                                                       data2[pix] = ((data2[pix]>>1) + 64) * r1 * div_2_255;
+                                               else
+                                                       data2[pix] = 255 - (191 - (data2[pix]>>1)) * (255-r1) * div_2_255;
+
+                                               if ((g1 = data[pix1=pix+1]) < 128)
+                                                       data2[pix1] = ((data2[pix1]>>1)+64) * g1 * div_2_255;
+                                               else
+                                                       data2[pix1] = 255 - (191 - (data2[pix1]>>1)) * (255-g1) * div_2_255;
+
+                                               if ((b1 = data[pix2=pix+2]) < 128)
+                                                       data2[pix2] = ((data2[pix2]>>1)+64) * b1 * div_2_255;
+                                               else
+                                                       data2[pix2] = 255 - (191 - (data2[pix2]>>1)) * (255-b1) * div_2_255;
+
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "hardlight" : 
+                                       var div_2_255 = 2 / 255;
+                                       while (p--) {
+                                               if ((r2 = data2[pix-=4]) < 128)
+                                                       data2[pix] = data[pix] * r2 * div_2_255;
+                                               else
+                                                       data2[pix] = 255 - (255-data[pix]) * (255-r2) * div_2_255;
+
+                                               if ((g2 = data2[pix1=pix+1]) < 128)
+                                                       data2[pix1] = data[pix1] * g2 * div_2_255;
+                                               else
+                                                       data2[pix1] = 255 - (255-data[pix1]) * (255-g2) * div_2_255;
+
+                                               if ((b2 = data2[pix2=pix+2]) < 128)
+                                                       data2[pix2] = data[pix2] * b2 * div_2_255;
+                                               else
+                                                       data2[pix2] = 255 - (255-data[pix2]) * (255-b2) * div_2_255;
+
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "colordodge" : 
+                                       while (p--) {
+                                               if ((r3 = (data[pix-=4]<<8)/(255-(r2 = data2[pix]))) > 255 || r2 == 255)
+                                                       data2[pix] = 255;
+                                               else
+                                                       data2[pix] = r3;
+
+                                               if ((g3 = (data[pix1=pix+1]<<8)/(255-(g2 = data2[pix1]))) > 255 || g2 == 255)
+                                                       data2[pix1] = 255;
+                                               else
+                                                       data2[pix1] = g3;
+
+                                               if ((b3 = (data[pix2=pix+2]<<8)/(255-(b2 = data2[pix2]))) > 255 || b2 == 255)
+                                                       data2[pix2] = 255;
+                                               else
+                                                       data2[pix2] = b3;
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "colorburn" : 
+                                       while (p--) {
+                                               if ((r3 = 255-((255-data[pix-=4])<<8)/data2[pix]) < 0 || data2[pix] == 0)
+                                                       data2[pix] = 0;
+                                               else
+                                                       data2[pix] = r3;
+
+                                               if ((g3 = 255-((255-data[pix1=pix+1])<<8)/data2[pix1]) < 0 || data2[pix1] == 0)
+                                                       data2[pix1] = 0;
+                                               else
+                                                       data2[pix1] = g3;
+
+                                               if ((b3 = 255-((255-data[pix2=pix+2])<<8)/data2[pix2]) < 0 || data2[pix2] == 0)
+                                                       data2[pix2] = 0;
+                                               else
+                                                       data2[pix2] = b3;
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "linearlight" : 
+                                       while (p--) {
+                                               if ( ((r3 = 2*(r2=data2[pix-=4])+data[pix]-256) < 0) || (r2 < 128 && r3 < 0)) {
+                                                       data2[pix] = 0
+                                               } else {
+                                                       if (r3 > 255)
+                                                               data2[pix] = 255;
+                                                       else
+                                                               data2[pix] = r3;
+                                               }
+                                               if ( ((g3 = 2*(g2=data2[pix1=pix+1])+data[pix1]-256) < 0) || (g2 < 128 && g3 < 0)) {
+                                                       data2[pix1] = 0
+                                               } else {
+                                                       if (g3 > 255)
+                                                               data2[pix1] = 255;
+                                                       else
+                                                               data2[pix1] = g3;
+                                               }
+                                               if ( ((b3 = 2*(b2=data2[pix2=pix+2])+data[pix2]-256) < 0) || (b2 < 128 && b3 < 0)) {
+                                                       data2[pix2] = 0
+                                               } else {
+                                                       if (b3 > 255)
+                                                               data2[pix2] = 255;
+                                                       else
+                                                               data2[pix2] = b3;
+                                               }
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "vividlight" : 
+                                       while (p--) {
+                                               if ((r2=data2[pix-=4]) < 128) {
+                                                       if (r2) {
+                                                               if ((r3 = 255 - ((255-data[pix])<<8) / (2*r2)) < 0) 
+                                                                       data2[pix] = 0;
+                                                               else
+                                                                       data2[pix] = r3
+                                                       } else {
+                                                               data2[pix] = 0;
+                                                       }
+                                               } else if ((r3 = (r4=2*r2-256)) < 255) {
+                                                       if ((r3 = (data[pix]<<8)/(255-r4)) > 255) 
+                                                               data2[pix] = 255;
+                                                       else
+                                                               data2[pix] = r3;
+                                               } else {
+                                                       if (r3 < 0) 
+                                                               data2[pix] = 0;
+                                                       else
+                                                               data2[pix] = r3
+                                               }
+
+                                               if ((g2=data2[pix1=pix+1]) < 128) {
+                                                       if (g2) {
+                                                               if ((g3 = 255 - ((255-data[pix1])<<8) / (2*g2)) < 0) 
+                                                                       data2[pix1] = 0;
+                                                               else
+                                                                       data2[pix1] = g3;
+                                                       } else {
+                                                               data2[pix1] = 0;
+                                                       }
+                                               } else if ((g3 = (g4=2*g2-256)) < 255) {
+                                                       if ((g3 = (data[pix1]<<8)/(255-g4)) > 255)
+                                                               data2[pix1] = 255;
+                                                       else
+                                                               data2[pix1] = g3;
+                                               } else {
+                                                       if (g3 < 0) 
+                                                               data2[pix1] = 0;
+                                                       else
+                                                               data2[pix1] = g3;
+                                               }
+
+                                               if ((b2=data2[pix2=pix+2]) < 128) {
+                                                       if (b2) {
+                                                               if ((b3 = 255 - ((255-data[pix2])<<8) / (2*b2)) < 0) 
+                                                                       data2[pix2] = 0;
+                                                               else
+                                                                       data2[pix2] = b3;
+                                                       } else {
+                                                               data2[pix2] = 0;
+                                                       }
+                                               } else if ((b3 = (b4=2*b2-256)) < 255) {
+                                                       if ((b3 = (data[pix2]<<8)/(255-b4)) > 255) 
+                                                               data2[pix2] = 255;
+                                                       else
+                                                               data2[pix2] = b3;
+                                               } else {
+                                                       if (b3 < 0) 
+                                                               data2[pix2] = 0;
+                                                       else
+                                                               data2[pix2] = b3;
+                                               }
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "pinlight" : 
+                                       while (p--) {
+                                               if ((r2=data2[pix-=4]) < 128)
+                                                       if ((r1=data[pix]) < (r4=2*r2))
+                                                               data2[pix] = r1;
+                                                       else
+                                                               data2[pix] = r4;
+                                               else
+                                                       if ((r1=data[pix]) > (r4=2*r2-256))
+                                                               data2[pix] = r1;
+                                                       else
+                                                               data2[pix] = r4;
+
+                                               if ((g2=data2[pix1=pix+1]) < 128)
+                                                       if ((g1=data[pix1]) < (g4=2*g2))
+                                                               data2[pix1] = g1;
+                                                       else
+                                                               data2[pix1] = g4;
+                                               else
+                                                       if ((g1=data[pix1]) > (g4=2*g2-256))
+                                                               data2[pix1] = g1;
+                                                       else
+                                                               data2[pix1] = g4;
+
+                                               if ((r2=data2[pix2=pix+2]) < 128)
+                                                       if ((r1=data[pix2]) < (r4=2*r2))
+                                                               data2[pix2] = r1;
+                                                       else
+                                                               data2[pix2] = r4;
+                                               else
+                                                       if ((r1=data[pix2]) > (r4=2*r2-256))
+                                                               data2[pix2] = r1;
+                                                       else
+                                                               data2[pix2] = r4;
+                                       }
+                                       dataChanged = true;
+                                       break;
+
+                               case "hardmix" : 
+                                       while (p--) {
+                                               if ((r2 = data2[pix-=4]) < 128)
+                                                       if (255 - ((255-data[pix])<<8)/(2*r2) < 128 || r2 == 0)
+                                                               data2[pix] = 0;
+                                                       else
+                                                               data2[pix] = 255;
+                                               else if ((r4=2*r2-256) < 255 && (data[pix]<<8)/(255-r4) < 128)
+                                                       data2[pix] = 0;
+                                               else
+                                                       data2[pix] = 255;
+
+                                               if ((g2 = data2[pix1=pix+1]) < 128)
+                                                       if (255 - ((255-data[pix1])<<8)/(2*g2) < 128 || g2 == 0)
+                                                               data2[pix1] = 0;
+                                                       else
+                                                               data2[pix1] = 255;
+                                               else if ((g4=2*g2-256) < 255 && (data[pix1]<<8)/(255-g4) < 128)
+                                                       data2[pix1] = 0;
+                                               else
+                                                       data2[pix1] = 255;
+
+                                               if ((b2 = data2[pix2=pix+2]) < 128)
+                                                       if (255 - ((255-data[pix2])<<8)/(2*b2) < 128 || b2 == 0)
+                                                               data2[pix2] = 0;
+                                                       else
+                                                               data2[pix2] = 255;
+                                               else if ((b4=2*b2-256) < 255 && (data[pix2]<<8)/(255-b4) < 128)
+                                                       data2[pix2] = 0;
+                                               else
+                                                       data2[pix2] = 255;
+                                       }
+                                       dataChanged = true;
+                                       break;
+                       }
+
+                       if (dataChanged) 
+                               otherCtx.putImageData(dataDesc2,0,0);
+
+                       var ctx = params.canvas.getContext("2d");
+                       ctx.save();
+                       ctx.globalAlpha = amount;
+                       ctx.drawImage(
+                               otherCanvas,
+                               0,0,rect.width,rect.height,
+                               rect.left,rect.top,rect.width,rect.height
+                       );
+                       ctx.globalAlpha = 1;
+                       ctx.restore();
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}/*
+ * Pixastic Lib - Blur filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.blur = {
+       process : function(params) {
+
+               if (typeof params.options.fixMargin == "undefined")
+                       params.options.fixMargin = true;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       /*
+                       var kernel = [
+                               [0.5,   1,      0.5],
+                               [1,     2,      1],
+                               [0.5,   1,      0.5]
+                       ];
+                       */
+
+                       var kernel = [
+                               [0,     1,      0],
+                               [1,     2,      1],
+                               [0,     1,      0]
+                       ];
+
+                       var weight = 0;
+                       for (var i=0;i<3;i++) {
+                               for (var j=0;j<3;j++) {
+                                       weight += kernel[i][j];
+                               }
+                       }
+
+                       weight = 1 / (weight*2);
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var prevY = (y == 1) ? 0 : y-2;
+                               var nextY = (y == h) ? y - 1 : y;
+
+                               var offsetYPrev = prevY*w*4;
+                               var offsetYNext = nextY*w*4;
+
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
+       
+                                       data[offset] = (
+                                               /*
+                                               dataCopy[offsetPrev - 4]
+                                               + dataCopy[offsetPrev+4] 
+                                               + dataCopy[offsetNext - 4]
+                                               + dataCopy[offsetNext+4]
+                                               + 
+                                               */
+                                               (dataCopy[offsetPrev]
+                                               + dataCopy[offset-4]
+                                               + dataCopy[offset+4]
+                                               + dataCopy[offsetNext])         * 2
+                                               + dataCopy[offset]              * 4
+                                               ) * weight;
+
+                                       data[offset+1] = (
+                                               /*
+                                               dataCopy[offsetPrev - 3]
+                                               + dataCopy[offsetPrev+5] 
+                                               + dataCopy[offsetNext - 3] 
+                                               + dataCopy[offsetNext+5]
+                                               + 
+                                               */
+                                               (dataCopy[offsetPrev+1]
+                                               + dataCopy[offset-3]
+                                               + dataCopy[offset+5]
+                                               + dataCopy[offsetNext+1])       * 2
+                                               + dataCopy[offset+1]            * 4
+                                               ) * weight;
+
+                                       data[offset+2] = (
+                                               /*
+                                               dataCopy[offsetPrev - 2] 
+                                               + dataCopy[offsetPrev+6] 
+                                               + dataCopy[offsetNext - 2] 
+                                               + dataCopy[offsetNext+6]
+                                               + 
+                                               */
+                                               (dataCopy[offsetPrev+2]
+                                               + dataCopy[offset-2]
+                                               + dataCopy[offset+6]
+                                               + dataCopy[offsetNext+2])       * 2
+                                               + dataCopy[offset+2]            * 4
+                                               ) * weight;
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=1.5)";
+
+                       if (params.options.fixMargin) {
+                               params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - 2 + "px";
+                               params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - 2 + "px";
+                       }
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
+       }
+}/*
+ * Pixastic Lib - Blur Fast - v0.1.1
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.blurfast = {
+       process : function(params) {
+
+               var amount = parseFloat(params.options.amount)||0;
+               var clear = !!(params.options.clear && params.options.clear != "false");
+
+               amount = Math.max(0,Math.min(5,amount));
+
+               if (Pixastic.Client.hasCanvas()) {
+                       var rect = params.options.rect;
+
+                       var ctx = params.canvas.getContext("2d");
+                       ctx.save();
+                       ctx.beginPath();
+                       ctx.rect(rect.left, rect.top, rect.width, rect.height);
+                       ctx.clip();
+
+                       var scale = 2;
+                       var smallWidth = Math.round(params.width / scale);
+                       var smallHeight = Math.round(params.height / scale);
+
+                       var copy = document.createElement("canvas");
+                       copy.width = smallWidth;
+                       copy.height = smallHeight;
+
+                       var clear = false;
+                       var steps = Math.round(amount * 20);
+
+                       var copyCtx = copy.getContext("2d");
+                       for (var i=0;i<steps;i++) {
+                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));
+                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));
+       
+                               copyCtx.clearRect(0,0,smallWidth,smallHeight);
+       
+                               copyCtx.drawImage(
+                                       params.canvas,
+                                       0,0,params.width,params.height,
+                                       0,0,scaledWidth,scaledHeight
+                               );
+       
+                               if (clear)
+                                       ctx.clearRect(rect.left,rect.top,rect.width,rect.height);
+       
+                               ctx.drawImage(
+                                       copy,
+                                       0,0,scaledWidth,scaledHeight,
+                                       0,0,params.width,params.height
+                               );
+                       }
+
+                       ctx.restore();
+
+                       params.useData = false;
+                       return true;
+               } else if (Pixastic.Client.isIE()) {
+                       var radius = 10 * amount;
+                       params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=" + radius + ")";
+
+                       if (params.options.fixMargin || 1) {
+                               params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - Math.round(radius) + "px";
+                               params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - Math.round(radius) + "px";
+                       }
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());
+       }
+}
+/*
+ * Pixastic Lib - Brightness/Contrast filter - v0.1.1
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.brightness = {
+
+       process : function(params) {
+
+               var brightness = parseInt(params.options.brightness,10) || 0;
+               var contrast = parseFloat(params.options.contrast)||0;
+               var legacy = !!(params.options.legacy && params.options.legacy != "false");
+
+               if (legacy) {
+                       brightness = Math.min(150,Math.max(-150,brightness));
+               } else {
+                       var brightMul = 1 + Math.min(150,Math.max(-150,brightness)) / 150;
+               }
+               contrast = Math.max(0,contrast+1);
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var p = w*h;
+                       var pix = p*4, pix1, pix2;
+
+                       var mul, add;
+                       if (contrast != 1) {
+                               if (legacy) {
+                                       mul = contrast;
+                                       add = (brightness - 128) * contrast + 128;
+                               } else {
+                                       mul = brightMul * contrast;
+                                       add = - contrast * 128 + 128;
+                               }
+                       } else {  // this if-then is not necessary anymore, is it?
+                               if (legacy) {
+                                       mul = 1;
+                                       add = brightness;
+                               } else {
+                                       mul = brightMul;
+                                       add = 0;
+                               }
+                       }
+                       var r, g, b;
+                       while (p--) {
+                               if ((r = data[pix-=4] * mul + add) > 255 )
+                                       data[pix] = 255;
+                               else if (r < 0)
+                                       data[pix] = 0;
+                               else
+                                       data[pix] = r;
+
+                               if ((g = data[pix1=pix+1] * mul + add) > 255 ) 
+                                       data[pix1] = 255;
+                               else if (g < 0)
+                                       data[pix1] = 0;
+                               else
+                                       data[pix1] = g;
+
+                               if ((b = data[pix2=pix+2] * mul + add) > 255 ) 
+                                       data[pix2] = 255;
+                               else if (b < 0)
+                                       data[pix2] = 0;
+                               else
+                                       data[pix2] = b;
+                       }
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
+/*
+ * Pixastic Lib - Color adjust filter - v0.1.1
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.coloradjust = {
+
+       process : function(params) {
+               var red = parseFloat(params.options.red) || 0;
+               var green = parseFloat(params.options.green) || 0;
+               var blue = parseFloat(params.options.blue) || 0;
+
+               red = Math.round(red*255);
+               green = Math.round(green*255);
+               blue = Math.round(blue*255);
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+
+                       var p = rect.width*rect.height;
+                       var pix = p*4, pix1, pix2;
+
+                       var r, g, b;
+                       while (p--) {
+                               pix -= 4;
+
+                               if (red) {
+                                       if ((r = data[pix] + red) < 0 ) 
+                                               data[pix] = 0;
+                                       else if (r > 255 ) 
+                                               data[pix] = 255;
+                                       else
+                                               data[pix] = r;
+                               }
+
+                               if (green) {
+                                       if ((g = data[pix1=pix+1] + green) < 0 ) 
+                                               data[pix1] = 0;
+                                       else if (g > 255 ) 
+                                               data[pix1] = 255;
+                                       else
+                                               data[pix1] = g;
+                               }
+
+                               if (blue) {
+                                       if ((b = data[pix2=pix+2] + blue) < 0 ) 
+                                               data[pix2] = 0;
+                                       else if (b > 255 ) 
+                                               data[pix2] = 255;
+                                       else
+                                               data[pix2] = b;
+                               }
+                       }
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData());
+       }
+}
+/*
+ * Pixastic Lib - Histogram - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+
+Pixastic.Actions.colorhistogram = {
+
+       array256 : function(default_value) {
+               arr = [];
+               for (var i=0; i<256; i++) { arr[i] = default_value; }
+               return arr
+       },
+       process : function(params) {
+               var values = [];
+               if (typeof params.options.returnValue != "object") {
+                       params.options.returnValue = {rvals:[], gvals:[], bvals:[]};
+               }
+               var paint = !!(params.options.paint);
+
+               var returnValue = params.options.returnValue;
+               if (typeof returnValue.values != "array") {
+                       returnValue.rvals = [];
+                       returnValue.gvals = [];
+                       returnValue.bvals = [];
+               }
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       params.useData = false;
+                       var rvals = this.array256(0);
+                       var gvals = this.array256(0);
+                       var bvals = this.array256(0);
+                       var rect = params.options.rect;
+
+                       var p = rect.width*rect.height;
+                       var pix = p*4;
+                       while (p--) {
+                               rvals[data[pix-=4]]++;
+                               gvals[data[pix+1]]++;
+                               bvals[data[pix+2]]++;
+                       }
+                       returnValue.rvals = rvals;
+                       returnValue.gvals = gvals;
+                       returnValue.bvals = bvals;
+
+                       if (paint) {
+                               var ctx = params.canvas.getContext("2d");
+                               var vals = [rvals, gvals, bvals];
+                               for (var v=0;v<3;v++) {
+                                       var yoff = (v+1) * params.height / 3;
+                                       var maxValue = 0;
+                                       for (var i=0;i<256;i++) {
+                                               if (vals[v][i] > maxValue)
+                                                       maxValue = vals[v][i];
+                                       }
+                                       var heightScale = params.height / 3 / maxValue;
+                                       var widthScale = params.width / 256;
+                                       if (v==0) ctx.fillStyle = "rgba(255,0,0,0.5)";
+                                       else if (v==1) ctx.fillStyle = "rgba(0,255,0,0.5)";
+                                       else if (v==2) ctx.fillStyle = "rgba(0,0,255,0.5)";
+                                       for (var i=0;i<256;i++) {
+                                               ctx.fillRect(
+                                                       i * widthScale, params.height - heightScale * vals[v][i] - params.height + yoff,
+                                                       widthScale, vals[v][i] * heightScale
+                                               );
+                                       }
+                               }
+                       }
+                       return true;
+               }
+       },
+
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}/*
+ * Pixastic Lib - Crop - v0.1.1
+ * Copyright (c) 2008-2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.crop = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvas()) {
+                       var rect = params.options.rect;
+
+                       var width = rect.width;
+                       var height = rect.height;
+                       var top = rect.top;
+                       var left = rect.left;
+
+                       if (typeof params.options.left != "undefined")
+                               left = parseInt(params.options.left,10);
+                       if (typeof params.options.top != "undefined")
+                               top = parseInt(params.options.top,10);
+                       if (typeof params.options.height != "undefined")
+                               width = parseInt(params.options.width,10);
+                       if (typeof params.options.height != "undefined")
+                               height = parseInt(params.options.height,10);
+
+                       if (left < 0) left = 0;
+                       if (left > params.width-1) left = params.width-1;
+
+                       if (top < 0) top = 0;
+                       if (top > params.height-1) top = params.height-1;
+
+                       if (width < 1) width = 1;
+                       if (left + width > params.width)
+                               width = params.width - left;
+
+                       if (height < 1) height = 1;
+                       if (top + height > params.height)
+                               height = params.height - top;
+
+                       var copy = document.createElement("canvas");
+                       copy.width = params.width;
+                       copy.height = params.height;
+                       copy.getContext("2d").drawImage(params.canvas,0,0);
+
+                       params.canvas.width = width;
+                       params.canvas.height = height;
+                       params.canvas.getContext("2d").clearRect(0,0,width,height);
+
+                       params.canvas.getContext("2d").drawImage(copy,
+                               left,top,width,height,
+                               0,0,width,height
+                       );
+
+                       params.useData = false;
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvas();
+       }
+}
+
+
+/*
+ * Pixastic Lib - Desaturation filter - v0.1.1
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.desaturate = {
+
+       process : function(params) {
+               var useAverage = !!(params.options.average && params.options.average != "false");
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var p = w*h;
+                       var pix = p*4, pix1, pix2;
+
+                       if (useAverage) {
+                               while (p--) 
+                                       data[pix-=4] = data[pix1=pix+1] = data[pix2=pix+2] = (data[pix]+data[pix1]+data[pix2])/3
+                       } else {
+                               while (p--)
+                                       data[pix-=4] = data[pix1=pix+1] = data[pix2=pix+2] = (data[pix]*0.3 + data[pix1]*0.59 + data[pix2]*0.11);
+                       }
+                       return true;
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " gray";
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
+       }
+}/*
+ * Pixastic Lib - Edge detection filter - v0.1.1
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.edges = {
+       process : function(params) {
+
+               var mono = !!(params.options.mono && params.options.mono != "false");
+               var invert = !!(params.options.invert && params.options.invert != "false");
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       var c = -1/8;
+                       var kernel = [
+                               [c,     c,      c],
+                               [c,     1,      c],
+                               [c,     c,      c]
+                       ];
+
+                       weight = 1/c;
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var nextY = (y == h) ? y - 1 : y;
+                               var prevY = (y == 1) ? 0 : y-2;
+
+                               var offsetYPrev = prevY*w*4;
+                               var offsetYNext = nextY*w*4;
+
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
+       
+                                       var r = ((dataCopy[offsetPrev-4]
+                                               + dataCopy[offsetPrev]
+                                               + dataCopy[offsetPrev+4]
+                                               + dataCopy[offset-4]
+                                               + dataCopy[offset+4]
+                                               + dataCopy[offsetNext-4]
+                                               + dataCopy[offsetNext]
+                                               + dataCopy[offsetNext+4]) * c
+                                               + dataCopy[offset]
+                                               ) 
+                                               * weight;
+       
+                                       var g = ((dataCopy[offsetPrev-3]
+                                               + dataCopy[offsetPrev+1]
+                                               + dataCopy[offsetPrev+5]
+                                               + dataCopy[offset-3]
+                                               + dataCopy[offset+5]
+                                               + dataCopy[offsetNext-3]
+                                               + dataCopy[offsetNext+1]
+                                               + dataCopy[offsetNext+5]) * c
+                                               + dataCopy[offset+1])
+                                               * weight;
+       
+                                       var b = ((dataCopy[offsetPrev-2]
+                                               + dataCopy[offsetPrev+2]
+                                               + dataCopy[offsetPrev+6]
+                                               + dataCopy[offset-2]
+                                               + dataCopy[offset+6]
+                                               + dataCopy[offsetNext-2]
+                                               + dataCopy[offsetNext+2]
+                                               + dataCopy[offsetNext+6]) * c
+                                               + dataCopy[offset+2])
+                                               * weight;
+
+                                       if (mono) {
+                                               var brightness = (r*0.3 + g*0.59 + b*0.11)||0;
+                                               if (invert) brightness = 255 - brightness;
+                                               if (brightness < 0 ) brightness = 0;
+                                               if (brightness > 255 ) brightness = 255;
+                                               r = g = b = brightness;
+                                       } else {
+                                               if (invert) {
+                                                       r = 255 - r;
+                                                       g = 255 - g;
+                                                       b = 255 - b;
+                                               }
+                                               if (r < 0 ) r = 0;
+                                               if (g < 0 ) g = 0;
+                                               if (b < 0 ) b = 0;
+                                               if (r > 255 ) r = 255;
+                                               if (g > 255 ) g = 255;
+                                               if (b > 255 ) b = 255;
+                                       }
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}/*
+ * Pixastic Lib - Edge detection 2 - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ * 
+ * Contribution by Oliver Hunt (http://nerget.com/, http://nerget.com/canvas/edgeDetection.js). Thanks Oliver!
+ *
+ */
+
+Pixastic.Actions.edges2 = {
+       process : function(params) {
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w * 4;
+                       var pixel = w4 + 4; // Start at (1,1)
+                       var hm1 = h - 1;
+                       var wm1 = w - 1;
+                       for (var y = 1; y < hm1; ++y) {
+                               // Prepare initial cached values for current row
+                               var centerRow = pixel - 4;
+                               var priorRow = centerRow - w4;
+                               var nextRow = centerRow + w4;
+                               
+                               var r1 = - dataCopy[priorRow]   - dataCopy[centerRow]   - dataCopy[nextRow];
+                               var g1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];
+                               var b1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];
+                               
+                               var rp = dataCopy[priorRow += 2];
+                               var gp = dataCopy[++priorRow];
+                               var bp = dataCopy[++priorRow];
+                               
+                               var rc = dataCopy[centerRow += 2];
+                               var gc = dataCopy[++centerRow];
+                               var bc = dataCopy[++centerRow];
+                               
+                               var rn = dataCopy[nextRow += 2];
+                               var gn = dataCopy[++nextRow];
+                               var bn = dataCopy[++nextRow];
+                               
+                               var r2 = - rp - rc - rn;
+                               var g2 = - gp - gc - gn;
+                               var b2 = - bp - bc - bn;
+                               
+                               // Main convolution loop
+                               for (var x = 1; x < wm1; ++x) {
+                                       centerRow = pixel + 4;
+                                       priorRow = centerRow - w4;
+                                       nextRow = centerRow + w4;
+                                       
+                                       var r = 127 + r1 - rp - (rc * -8) - rn;
+                                       var g = 127 + g1 - gp - (gc * -8) - gn;
+                                       var b = 127 + b1 - bp - (bc * -8) - bn;
+                                       
+                                       r1 = r2;
+                                       g1 = g2;
+                                       b1 = b2;
+                                       
+                                       rp = dataCopy[  priorRow];
+                                       gp = dataCopy[++priorRow];
+                                       bp = dataCopy[++priorRow];
+                                       
+                                       rc = dataCopy[  centerRow];
+                                       gc = dataCopy[++centerRow];
+                                       bc = dataCopy[++centerRow];
+                                       
+                                       rn = dataCopy[  nextRow];
+                                       gn = dataCopy[++nextRow];
+                                       bn = dataCopy[++nextRow];
+                                       
+                                       r += (r2 = - rp - rc - rn);
+                                       g += (g2 = - gp - gc - gn);
+                                       b += (b2 = - bp - bc - bn);
+
+                                       if (r > 255) r = 255;
+                                       if (g > 255) g = 255;
+                                       if (b > 255) b = 255;
+                                       if (r < 0) r = 0;
+                                       if (g < 0) g = 0;
+                                       if (b < 0) b = 0;
+
+                                       data[pixel] = r;
+                                       data[++pixel] = g;
+                                       data[++pixel] = b;
+                                       //data[++pixel] = 255; // alpha
+
+                                       pixel+=2;
+                               }
+                               pixel += 8;
+                       }
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}/*
+ * Pixastic Lib - Emboss filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.emboss = {
+       process : function(params) {
+
+               var strength = parseFloat(params.options.strength)||1;
+               var greyLevel = typeof params.options.greyLevel != "undefined" ? parseInt(params.options.greyLevel) : 180;
+               var direction = params.options.direction||"topleft";
+               var blend = !!(params.options.blend && params.options.blend != "false");
+
+               var dirY = 0;
+               var dirX = 0;
+
+               switch (direction) {
+                       case "topleft":                 // top left
+                               dirY = -1;
+                               dirX = -1;
+                               break;
+                       case "top":                     // top
+                               dirY = -1;
+                               dirX = 0;
+                               break;
+                       case "topright":                        // top right
+                               dirY = -1;
+                               dirX = 1;
+                               break;
+                       case "right":                   // right
+                               dirY = 0;
+                               dirX = 1;
+                               break;
+                       case "bottomright":                     // bottom right
+                               dirY = 1;
+                               dirX = 1;
+                               break;
+                       case "bottom":                  // bottom
+                               dirY = 1;
+                               dirX = 0;
+                               break;
+                       case "bottomleft":                      // bottom left
+                               dirY = 1;
+                               dirX = -1;
+                               break;
+                       case "left":                    // left
+                               dirY = 0;
+                               dirX = -1;
+                               break;
+               }
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       var invertAlpha = !!params.options.invertAlpha;
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var otherY = dirY;
+                               if (y + otherY < 1) otherY = 0;
+                               if (y + otherY > h) otherY = 0;
+
+                               var offsetYOther = (y-1+otherY)*w*4;
+
+                               var x = w;
+                               do {
+                                               var offset = offsetY + (x-1)*4;
+
+                                               var otherX = dirX;
+                                               if (x + otherX < 1) otherX = 0;
+                                               if (x + otherX > w) otherX = 0;
+
+                                               var offsetOther = offsetYOther + (x-1+otherX)*4;
+
+                                               var dR = dataCopy[offset] - dataCopy[offsetOther];
+                                               var dG = dataCopy[offset+1] - dataCopy[offsetOther+1];
+                                               var dB = dataCopy[offset+2] - dataCopy[offsetOther+2];
+
+                                               var dif = dR;
+                                               var absDif = dif > 0 ? dif : -dif;
+
+                                               var absG = dG > 0 ? dG : -dG;
+                                               var absB = dB > 0 ? dB : -dB;
+
+                                               if (absG > absDif) {
+                                                       dif = dG;
+                                               }
+                                               if (absB > absDif) {
+                                                       dif = dB;
+                                               }
+
+                                               dif *= strength;
+
+                                               if (blend) {
+                                                       var r = data[offset] + dif;
+                                                       var g = data[offset+1] + dif;
+                                                       var b = data[offset+2] + dif;
+
+                                                       data[offset] = (r > 255) ? 255 : (r < 0 ? 0 : r);
+                                                       data[offset+1] = (g > 255) ? 255 : (g < 0 ? 0 : g);
+                                                       data[offset+2] = (b > 255) ? 255 : (b < 0 ? 0 : b);
+                                               } else {
+                                                       var grey = greyLevel - dif;
+                                                       if (grey < 0) {
+                                                               grey = 0;
+                                                       } else if (grey > 255) {
+                                                               grey = 255;
+                                                       }
+
+                                                       data[offset] = data[offset+1] = data[offset+2] = grey;
+                                               }
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " progid:DXImageTransform.Microsoft.emboss()";
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
+       }
+
+}
+/*
+ * Pixastic Lib - Flip - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.flip = {
+       process : function(params) {
+               var rect = params.options.rect;
+               var copyCanvas = document.createElement("canvas");
+               copyCanvas.width = rect.width;
+               copyCanvas.height = rect.height;
+               copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);
+
+               var ctx = params.canvas.getContext("2d");
+               ctx.clearRect(rect.left, rect.top, rect.width, rect.height);
+
+               if (params.options.axis == "horizontal") {
+                       ctx.scale(-1,1);
+                       ctx.drawImage(copyCanvas, -rect.left-rect.width, rect.top, rect.width, rect.height)
+               } else {
+                       ctx.scale(1,-1);
+                       ctx.drawImage(copyCanvas, rect.left, -rect.top-rect.height, rect.width, rect.height)
+               }
+
+               params.useData = false;
+
+               return true;            
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvas();
+       }
+}
+
+/*
+ * Pixastic Lib - Horizontal flip - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.fliph = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvas()) {
+                       var rect = params.options.rect;
+                       var copyCanvas = document.createElement("canvas");
+                       copyCanvas.width = rect.width;
+                       copyCanvas.height = rect.height;
+                       copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);
+
+                       var ctx = params.canvas.getContext("2d");
+                       ctx.clearRect(rect.left, rect.top, rect.width, rect.height);
+                       ctx.scale(-1,1);
+                       ctx.drawImage(copyCanvas, -rect.left-rect.width, rect.top, rect.width, rect.height)
+                       params.useData = false;
+
+                       return true;            
+
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " fliph";
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());
+       }
+}
+
+/*
+ * Pixastic Lib - Vertical flip - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.flipv = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvas()) {
+                       var rect = params.options.rect;
+                       var copyCanvas = document.createElement("canvas");
+                       copyCanvas.width = rect.width;
+                       copyCanvas.height = rect.height;
+                       copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);
+
+                       var ctx = params.canvas.getContext("2d");
+                       ctx.clearRect(rect.left, rect.top, rect.width, rect.height);
+                       ctx.scale(1,-1);
+                       ctx.drawImage(copyCanvas, rect.left, -rect.top-rect.height, rect.width, rect.height)
+                       params.useData = false;
+
+                       return true;            
+
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " flipv";
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());
+       }
+}
+
+/*
+ * Pixastic Lib - Glow - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+
+Pixastic.Actions.glow = {
+       process : function(params) {
+
+               var amount = (parseFloat(params.options.amount)||0);
+               var blurAmount = parseFloat(params.options.radius)||0;
+
+               amount = Math.min(1,Math.max(0,amount));
+               blurAmount = Math.min(5,Math.max(0,blurAmount));
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var rect = params.options.rect;
+
+                       var blurCanvas = document.createElement("canvas");
+                       blurCanvas.width = params.width;
+                       blurCanvas.height = params.height;
+                       var blurCtx = blurCanvas.getContext("2d");
+                       blurCtx.drawImage(params.canvas,0,0);
+
+                       var scale = 2;
+                       var smallWidth = Math.round(params.width / scale);
+                       var smallHeight = Math.round(params.height / scale);
+
+                       var copy = document.createElement("canvas");
+                       copy.width = smallWidth;
+                       copy.height = smallHeight;
+
+                       var clear = true;
+                       var steps = Math.round(blurAmount * 20);
+
+                       var copyCtx = copy.getContext("2d");
+                       for (var i=0;i<steps;i++) {
+                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));
+                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));
+       
+                               copyCtx.clearRect(0,0,smallWidth,smallHeight);
+       
+                               copyCtx.drawImage(
+                                       blurCanvas,
+                                       0,0,params.width,params.height,
+                                       0,0,scaledWidth,scaledHeight
+                               );
+       
+                               blurCtx.clearRect(0,0,params.width,params.height);
+       
+                               blurCtx.drawImage(
+                                       copy,
+                                       0,0,scaledWidth,scaledHeight,
+                                       0,0,params.width,params.height
+                               );
+                       }
+
+                       var data = Pixastic.prepareData(params);
+                       var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var r = data[offset] + amount * blurData[offset];
+                                       var g = data[offset+1] + amount * blurData[offset+1];
+                                       var b = data[offset+2] + amount * blurData[offset+2];
+       
+                                       if (r > 255) r = 255;
+                                       if (g > 255) g = 255;
+                                       if (b > 255) b = 255;
+                                       if (r < 0) r = 0;
+                                       if (g < 0) g = 0;
+                                       if (b < 0) b = 0;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
+
+
+/*
+ * Pixastic Lib - Histogram - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.histogram = {
+       process : function(params) {
+
+               var average = !!(params.options.average && params.options.average != "false");
+               var paint = !!(params.options.paint && params.options.paint != "false");
+               var color = params.options.color || "rgba(255,255,255,0.5)";
+               var values = [];
+               if (typeof params.options.returnValue != "object") {
+                       params.options.returnValue = {values:[]};
+               }
+               var returnValue = params.options.returnValue;
+               if (typeof returnValue.values != "array") {
+                       returnValue.values = [];
+               }
+               values = returnValue.values;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       params.useData = false;
+
+                       for (var i=0;i<256;i++) {
+                               values[i] = 0;
+                       }
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+                                       var brightness = average ? 
+                                               Math.round((data[offset]+data[offset+1]+data[offset+2])/3)
+                                               : Math.round(data[offset]*0.3 + data[offset+1]*0.59 + data[offset+2]*0.11);
+                                       values[brightness]++;
+
+                               } while (--x);
+                       } while (--y);
+
+                       if (paint) {
+                               var maxValue = 0;
+                               for (var i=0;i<256;i++) {
+                                       if (values[i] > maxValue) {
+                                               maxValue = values[i];
+                                       }
+                               }
+                               var heightScale = params.height / maxValue;
+                               var widthScale = params.width / 256;
+                               var ctx = params.canvas.getContext("2d");
+                               ctx.fillStyle = color;
+                               for (var i=0;i<256;i++) {
+                                       ctx.fillRect(
+                                               i * widthScale, params.height - heightScale * values[i],
+                                               widthScale, values[i] * heightScale
+                                       );
+                               }
+                       }
+
+                       returnValue.values = values;
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+/*
+ * Pixastic Lib - HSL Adjust  - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.hsl = {
+       process : function(params) {
+
+               var hue = parseInt(params.options.hue,10)||0;
+               var saturation = (parseInt(params.options.saturation,10)||0) / 100;
+               var lightness = (parseInt(params.options.lightness,10)||0) / 100;
+
+
+               // this seems to give the same result as Photoshop
+               if (saturation < 0) {
+                       var satMul = 1+saturation;
+               } else {
+                       var satMul = 1+saturation*2;
+               }
+
+               hue = (hue%360) / 360;
+               var hue6 = hue * 6;
+
+               var rgbDiv = 1 / 255;
+
+               var light255 = lightness * 255;
+               var lightp1 = 1 + lightness;
+               var lightm1 = 1 - lightness;
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var r = data[offset];
+                                       var g = data[offset+1];
+                                       var b = data[offset+2];
+
+                                       if (hue != 0 || saturation != 0) {
+                                               // ok, here comes rgb to hsl + adjust + hsl to rgb, all in one jumbled mess. 
+                                               // It's not so pretty, but it's been optimized to get somewhat decent performance.
+                                               // The transforms were originally adapted from the ones found in Graphics Gems, but have been heavily modified.
+                                               var vs = r;
+                                               if (g > vs) vs = g;
+                                               if (b > vs) vs = b;
+                                               var ms = r;
+                                               if (g < ms) ms = g;
+                                               if (b < ms) ms = b;
+                                               var vm = (vs-ms);
+                                               var l = (ms+vs)/255 * 0.5;
+                                               if (l > 0) {
+                                                       if (vm > 0) {
+                                                               if (l <= 0.5) {
+                                                                       var s = vm / (vs+ms) * satMul;
+                                                                       if (s > 1) s = 1;
+                                                                       var v = (l * (1+s));
+                                                               } else {
+                                                                       var s = vm / (510-vs-ms) * satMul;
+                                                                       if (s > 1) s = 1;
+                                                                       var v = (l+s - l*s);
+                                                               }
+                                                               if (r == vs) {
+                                                                       if (g == ms)
+                                                                               var h = 5 + ((vs-b)/vm) + hue6;
+                                                                       else
+                                                                               var h = 1 - ((vs-g)/vm) + hue6;
+                                                               } else if (g == vs) {
+                                                                       if (b == ms)
+                                                                               var h = 1 + ((vs-r)/vm) + hue6;
+                                                                       else
+                                                                               var h = 3 - ((vs-b)/vm) + hue6;
+                                                               } else {
+                                                                       if (r == ms)
+                                                                               var h = 3 + ((vs-g)/vm) + hue6;
+                                                                       else
+                                                                               var h = 5 - ((vs-r)/vm) + hue6;
+                                                               }
+                                                               if (h < 0) h+=6;
+                                                               if (h >= 6) h-=6;
+                                                               var m = (l+l-v);
+                                                               var sextant = h>>0;
+                                                               switch (sextant) {
+                                                                       case 0: r = v*255; g = (m+((v-m)*(h-sextant)))*255; b = m*255; break;
+                                                                       case 1: r = (v-((v-m)*(h-sextant)))*255; g = v*255; b = m*255; break;
+                                                                       case 2: r = m*255; g = v*255; b = (m+((v-m)*(h-sextant)))*255; break;
+                                                                       case 3: r = m*255; g = (v-((v-m)*(h-sextant)))*255; b = v*255; break;
+                                                                       case 4: r = (m+((v-m)*(h-sextant)))*255; g = m*255; b = v*255; break;
+                                                                       case 5: r = v*255; g = m*255; b = (v-((v-m)*(h-sextant)))*255; break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+
+                                       if (lightness < 0) {
+                                               r *= lightp1;
+                                               g *= lightp1;
+                                               b *= lightp1;
+                                       } else if (lightness > 0) {
+                                               r = r * lightm1 + light255;
+                                               g = g * lightm1 + light255;
+                                               b = b * lightm1 + light255;
+                                       }
+
+                                       if (r < 0) r = 0;
+                                       if (g < 0) g = 0;
+                                       if (b < 0) b = 0;
+                                       if (r > 255) r = 255;
+                                       if (g > 255) g = 255;
+                                       if (b > 255) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+
+}
+/*
+ * Pixastic Lib - Invert filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.invert = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+
+                       var invertAlpha = !!params.options.invertAlpha;
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+                                       data[offset] = 255 - data[offset];
+                                       data[offset+1] = 255 - data[offset+1];
+                                       data[offset+2] = 255 - data[offset+2];
+                                       if (invertAlpha) data[offset+3] = 255 - data[offset+3];
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               } else if (Pixastic.Client.isIE()) {
+                       params.image.style.filter += " invert";
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
+       }
+}
+/*
+ * Pixastic Lib - Laplace filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.laplace = {
+       process : function(params) {
+
+               var strength = 1.0;
+               var invert = !!(params.options.invert && params.options.invert != "false");
+               var contrast = parseFloat(params.options.edgeStrength)||0;
+
+               var greyLevel = parseInt(params.options.greyLevel)||0;
+
+               contrast = -contrast;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       var kernel = [
+                               [-1,    -1,     -1],
+                               [-1,    8,      -1],
+                               [-1,    -1,     -1]
+                       ];
+
+                       var weight = 1/8;
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var nextY = (y == h) ? y - 1 : y;
+                               var prevY = (y == 1) ? 0 : y-2;
+
+                               var offsetYPrev = prevY*w*4;
+                               var offsetYNext = nextY*w*4;
+
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
+       
+                                       var r = ((-dataCopy[offsetPrev-4]
+                                               - dataCopy[offsetPrev]
+                                               - dataCopy[offsetPrev+4]
+                                               - dataCopy[offset-4]
+                                               - dataCopy[offset+4]
+                                               - dataCopy[offsetNext-4]
+                                               - dataCopy[offsetNext]
+                                               - dataCopy[offsetNext+4])
+                                               + dataCopy[offset] * 8) 
+                                               * weight;
+       
+                                       var g = ((-dataCopy[offsetPrev-3]
+                                               - dataCopy[offsetPrev+1]
+                                               - dataCopy[offsetPrev+5]
+                                               - dataCopy[offset-3]
+                                               - dataCopy[offset+5]
+                                               - dataCopy[offsetNext-3]
+                                               - dataCopy[offsetNext+1]
+                                               - dataCopy[offsetNext+5])
+                                               + dataCopy[offset+1] * 8)
+                                               * weight;
+       
+                                       var b = ((-dataCopy[offsetPrev-2]
+                                               - dataCopy[offsetPrev+2]
+                                               - dataCopy[offsetPrev+6]
+                                               - dataCopy[offset-2]
+                                               - dataCopy[offset+6]
+                                               - dataCopy[offsetNext-2]
+                                               - dataCopy[offsetNext+2]
+                                               - dataCopy[offsetNext+6])
+                                               + dataCopy[offset+2] * 8)
+                                               * weight;
+
+                                       var brightness = ((r + g + b)/3) + greyLevel;
+
+                                       if (contrast != 0) {
+                                               if (brightness > 127) {
+                                                       brightness += ((brightness + 1) - 128) * contrast;
+                                               } else if (brightness < 127) {
+                                                       brightness -= (brightness + 1) * contrast;
+                                               }
+                                       }
+                                       if (invert) {
+                                               brightness = 255 - brightness;
+                                       }
+                                       if (brightness < 0 ) brightness = 0;
+                                       if (brightness > 255 ) brightness = 255;
+
+                                       data[offset] = data[offset+1] = data[offset+2] = brightness;
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
+/*
+ * Pixastic Lib - Lighten filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.lighten = {
+
+       process : function(params) {
+               var amount = parseFloat(params.options.amount) || 0;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+
+                                       var r = data[offset];
+                                       var g = data[offset+1];
+                                       var b = data[offset+2];
+
+                                       r += r*amount;
+                                       g += g*amount;
+                                       b += b*amount;
+
+                                       if (r < 0 ) r = 0;
+                                       if (g < 0 ) g = 0;
+                                       if (b < 0 ) b = 0;
+                                       if (r > 255 ) r = 255;
+                                       if (g > 255 ) g = 255;
+                                       if (b > 255 ) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+
+               } else if (Pixastic.Client.isIE()) {
+                       var img = params.image;
+                       if (amount < 0) {
+                               img.style.filter += " light()";
+                               img.filters[img.filters.length-1].addAmbient(
+                                       255,255,255,
+                                       100 * -amount
+                               );
+                       } else if (amount > 0) {
+                               img.style.filter += " light()";
+                               img.filters[img.filters.length-1].addAmbient(
+                                       255,255,255,
+                                       100
+                               );
+                               img.filters[img.filters.length-1].addAmbient(
+                                       255,255,255,
+                                       100 * amount
+                               );
+                       }
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
+       }
+}
+/*
+ * Pixastic Lib - Mosaic filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.mosaic = {
+
+       process : function(params) {
+               var blockSize = Math.max(1,parseInt(params.options.blockSize,10));
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+
+                       var ctx = params.canvas.getContext("2d");
+
+                       var pixel = document.createElement("canvas");
+                       pixel.width = pixel.height = 1;
+                       var pixelCtx = pixel.getContext("2d");
+
+                       var copy = document.createElement("canvas");
+                       copy.width = w;
+                       copy.height = h;
+                       var copyCtx = copy.getContext("2d");
+                       copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);
+
+                       for (var y=0;y<h;y+=blockSize) {
+                               for (var x=0;x<w;x+=blockSize) {
+                                       var blockSizeX = blockSize;
+                                       var blockSizeY = blockSize;
+               
+                                       if (blockSizeX + x > w)
+                                               blockSizeX = w - x;
+                                       if (blockSizeY + y > h)
+                                               blockSizeY = h - y;
+
+                                       pixelCtx.drawImage(copy, x, y, blockSizeX, blockSizeY, 0, 0, 1, 1);
+                                       var data = pixelCtx.getImageData(0,0,1,1).data;
+                                       ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";
+                                       ctx.fillRect(rect.left + x, rect.top + y, blockSize, blockSize);
+                               }
+                       }
+                       params.useData = false;
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData());
+       }
+}/*
+ * Pixastic Lib - Noise filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.noise = {
+
+       process : function(params) {
+               var amount = 0;
+               var strength = 0;
+               var mono = false;
+
+               if (typeof params.options.amount != "undefined")
+                       amount = parseFloat(params.options.amount)||0;
+               if (typeof params.options.strength != "undefined")
+                       strength = parseFloat(params.options.strength)||0;
+               if (typeof params.options.mono != "undefined")
+                       mono = !!(params.options.mono && params.options.mono != "false");
+
+               amount = Math.max(0,Math.min(1,amount));
+               strength = Math.max(0,Math.min(1,strength));
+
+               var noise = 128 * strength;
+               var noise2 = noise / 2;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       var random = Math.random;
+
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+                                       if (random() < amount) {
+                                               if (mono) {
+                                                       var pixelNoise = - noise2 + random() * noise;
+                                                       var r = data[offset] + pixelNoise;
+                                                       var g = data[offset+1] + pixelNoise;
+                                                       var b = data[offset+2] + pixelNoise;
+                                               } else {
+                                                       var r = data[offset] - noise2 + (random() * noise);
+                                                       var g = data[offset+1] - noise2 + (random() * noise);
+                                                       var b = data[offset+2] - noise2 + (random() * noise);
+                                               }
+
+                                               if (r < 0 ) r = 0;
+                                               if (g < 0 ) g = 0;
+                                               if (b < 0 ) b = 0;
+                                               if (r > 255 ) r = 255;
+                                               if (g > 255 ) g = 255;
+                                               if (b > 255 ) b = 255;
+
+                                               data[offset] = r;
+                                               data[offset+1] = g;
+                                               data[offset+2] = b;
+                                       }
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
+/*
+ * Pixastic Lib - Posterize effect - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.posterize = {
+
+       process : function(params) {
+
+               
+               var numLevels = 256;
+               if (typeof params.options.levels != "undefined")
+                       numLevels = parseInt(params.options.levels,10)||1;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+
+                       numLevels = Math.max(2,Math.min(256,numLevels));
+       
+                       var numAreas = 256 / numLevels;
+                       var numValues = 256 / (numLevels-1);
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+
+                                       var r = numValues * ((data[offset] / numAreas)>>0);
+                                       var g = numValues * ((data[offset+1] / numAreas)>>0);
+                                       var b = numValues * ((data[offset+2] / numAreas)>>0);
+
+                                       if (r > 255) r = 255;
+                                       if (g > 255) g = 255;
+                                       if (b > 255) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
+
+/*
+ * Pixastic Lib - Pointillize filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.pointillize = {
+
+       process : function(params) {
+               var radius = Math.max(1,parseInt(params.options.radius,10));
+               var density = Math.min(5,Math.max(0,parseFloat(params.options.density)||0));
+               var noise = Math.max(0,parseFloat(params.options.noise)||0);
+               var transparent = !!(params.options.transparent && params.options.transparent != "false");
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+
+                       var ctx = params.canvas.getContext("2d");
+                       var canvasWidth = params.canvas.width;
+                       var canvasHeight = params.canvas.height;
+
+                       var pixel = document.createElement("canvas");
+                       pixel.width = pixel.height = 1;
+                       var pixelCtx = pixel.getContext("2d");
+
+                       var copy = document.createElement("canvas");
+                       copy.width = w;
+                       copy.height = h;
+                       var copyCtx = copy.getContext("2d");
+                       copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);
+
+                       var diameter = radius * 2;
+
+                       if (transparent)
+                               ctx.clearRect(rect.left, rect.top, rect.width, rect.height);
+
+                       var noiseRadius = radius * noise;
+
+                       var dist = 1 / density;
+
+                       for (var y=0;y<h+radius;y+=diameter*dist) {
+                               for (var x=0;x<w+radius;x+=diameter*dist) {
+                                       rndX = noise ? (x+((Math.random()*2-1) * noiseRadius))>>0 : x;
+                                       rndY = noise ? (y+((Math.random()*2-1) * noiseRadius))>>0 : y;
+
+                                       var pixX = rndX - radius;
+                                       var pixY = rndY - radius;
+                                       if (pixX < 0) pixX = 0;
+                                       if (pixY < 0) pixY = 0;
+
+                                       var cx = rndX + rect.left;
+                                       var cy = rndY + rect.top;
+                                       if (cx < 0) cx = 0;
+                                       if (cx > canvasWidth) cx = canvasWidth;
+                                       if (cy < 0) cy = 0;
+                                       if (cy > canvasHeight) cy = canvasHeight;
+
+                                       var diameterX = diameter;
+                                       var diameterY = diameter;
+
+                                       if (diameterX + pixX > w)
+                                               diameterX = w - pixX;
+                                       if (diameterY + pixY > h)
+                                               diameterY = h - pixY;
+                                       if (diameterX < 1) diameterX = 1;
+                                       if (diameterY < 1) diameterY = 1;
+
+                                       pixelCtx.drawImage(copy, pixX, pixY, diameterX, diameterY, 0, 0, 1, 1);
+                                       var data = pixelCtx.getImageData(0,0,1,1).data;
+
+                                       ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";
+                                       ctx.beginPath();
+                                       ctx.arc(cx, cy, radius, 0, Math.PI*2, true);
+                                       ctx.closePath();
+                                       ctx.fill();
+                               }
+                       }
+
+                       params.useData = false;
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData());
+       }
+}/*
+ * Pixastic Lib - Resize - v0.1.0
+ * Copyright (c) 2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.resize = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvas()) {
+                       var width = parseInt(params.options.width,10);
+                       var height = parseInt(params.options.height,10);
+                       var canvas = params.canvas;
+
+                       if (width < 1) width = 1;
+                       if (width < 2) width = 2;
+
+                       var copy = document.createElement("canvas");
+                       copy.width = width;
+                       copy.height = height;
+
+                       copy.getContext("2d").drawImage(canvas,0,0,width,height);
+                       canvas.width = width;
+                       canvas.height = height;
+
+                       canvas.getContext("2d").drawImage(copy,0,0);
+
+                       params.useData = false;
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvas();
+       }
+}
+
+
+/*
+ * Pixastic Lib - Remove noise - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.removenoise = {
+       process : function(params) {
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var nextY = (y == h) ? y - 1 : y;
+                               var prevY = (y == 1) ? 0 : y-2;
+
+                               var offsetYPrev = prevY*w*4;
+                               var offsetYNext = nextY*w*4;
+
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
+
+                                       var minR, maxR, minG, maxG, minB, maxB;
+
+                                       minR = maxR = data[offsetPrev];
+                                       var r1 = data[offset-4], r2 = data[offset+4], r3 = data[offsetNext];
+                                       if (r1 < minR) minR = r1;
+                                       if (r2 < minR) minR = r2;
+                                       if (r3 < minR) minR = r3;
+                                       if (r1 > maxR) maxR = r1;
+                                       if (r2 > maxR) maxR = r2;
+                                       if (r3 > maxR) maxR = r3;
+
+                                       minG = maxG = data[offsetPrev+1];
+                                       var g1 = data[offset-3], g2 = data[offset+5], g3 = data[offsetNext+1];
+                                       if (g1 < minG) minG = g1;
+                                       if (g2 < minG) minG = g2;
+                                       if (g3 < minG) minG = g3;
+                                       if (g1 > maxG) maxG = g1;
+                                       if (g2 > maxG) maxG = g2;
+                                       if (g3 > maxG) maxG = g3;
+
+                                       minB = maxB = data[offsetPrev+2];
+                                       var b1 = data[offset-2], b2 = data[offset+6], b3 = data[offsetNext+2];
+                                       if (b1 < minB) minB = b1;
+                                       if (b2 < minB) minB = b2;
+                                       if (b3 < minB) minB = b3;
+                                       if (b1 > maxB) maxB = b1;
+                                       if (b2 > maxB) maxB = b2;
+                                       if (b3 > maxB) maxB = b3;
+
+                                       if (data[offset] > maxR) {
+                                               data[offset] = maxR;
+                                       } else if (data[offset] < minR) {
+                                               data[offset] = minR;
+                                       }
+                                       if (data[offset+1] > maxG) {
+                                               data[offset+1] = maxG;
+                                       } else if (data[offset+1] < minG) {
+                                               data[offset+1] = minG;
+                                       }
+                                       if (data[offset+2] > maxB) {
+                                               data[offset+2] = maxB;
+                                       } else if (data[offset+2] < minB) {
+                                               data[offset+2] = minB;
+                                       }
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}/*
+ * Pixastic Lib - Rotate - v0.1.0
+ * Copyright (c) 2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.rotate = {
+       process : function(params) {
+               if (Pixastic.Client.hasCanvas()) {
+                       var canvas = params.canvas;
+
+                       var width = params.width;
+                       var height = params.height;
+
+                       var copy = document.createElement("canvas");
+                       copy.width = width;
+                       copy.height = height;
+                       copy.getContext("2d").drawImage(canvas,0,0,width,height);
+
+                       var angle = -parseFloat(params.options.angle) * Math.PI / 180;
+
+                       var dimAngle = angle;
+                       if (dimAngle > Math.PI*0.5)
+                               dimAngle = Math.PI - dimAngle;
+                       if (dimAngle < -Math.PI*0.5)
+                               dimAngle = -Math.PI - dimAngle;
+
+                       var diag = Math.sqrt(width*width + height*height);
+
+                       var diagAngle1 = Math.abs(dimAngle) - Math.abs(Math.atan2(height, width));
+                       var diagAngle2 = Math.abs(dimAngle) + Math.abs(Math.atan2(height, width));
+
+                       var newWidth = Math.abs(Math.cos(diagAngle1) * diag);
+                       var newHeight = Math.abs(Math.sin(diagAngle2) * diag);
+
+                       canvas.width = newWidth;
+                       canvas.height = newHeight;
+
+                       var ctx = canvas.getContext("2d");
+                       ctx.translate(newWidth/2, newHeight/2);
+                       ctx.rotate(angle);
+                       ctx.drawImage(copy,-width/2,-height/2);
+
+                       params.useData = false;
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvas();
+       }
+}
+
+
+/*
+ * Pixastic Lib - Sepia filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.sepia = {
+
+       process : function(params) {
+               var mode = (parseInt(params.options.mode,10)||0);
+               if (mode < 0) mode = 0;
+               if (mode > 1) mode = 1;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+
+                                       if (mode) {
+                                               // a bit faster, but not as good
+                                               var d = data[offset] * 0.299 + data[offset+1] * 0.587 + data[offset+2] * 0.114;
+                                               var r = (d + 39);
+                                               var g = (d + 14);
+                                               var b = (d - 36);
+                                       } else {
+                                               // Microsoft
+                                               var or = data[offset];
+                                               var og = data[offset+1];
+                                               var ob = data[offset+2];
+       
+                                               var r = (or * 0.393 + og * 0.769 + ob * 0.189);
+                                               var g = (or * 0.349 + og * 0.686 + ob * 0.168);
+                                               var b = (or * 0.272 + og * 0.534 + ob * 0.131);
+                                       }
+
+                                       if (r < 0) r = 0; if (r > 255) r = 255;
+                                       if (g < 0) g = 0; if (g > 255) g = 255;
+                                       if (b < 0) b = 0; if (b > 255) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}/*
+ * Pixastic Lib - Sharpen filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.sharpen = {
+       process : function(params) {
+
+               var strength = 0;
+               if (typeof params.options.amount != "undefined")
+                       strength = parseFloat(params.options.amount)||0;
+
+               if (strength < 0) strength = 0;
+               if (strength > 1) strength = 1;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var dataCopy = Pixastic.prepareData(params, true)
+
+                       var mul = 15;
+                       var mulOther = 1 + 3*strength;
+
+                       var kernel = [
+                               [0,     -mulOther,      0],
+                               [-mulOther,     mul,    -mulOther],
+                               [0,     -mulOther,      0]
+                       ];
+
+                       var weight = 0;
+                       for (var i=0;i<3;i++) {
+                               for (var j=0;j<3;j++) {
+                                       weight += kernel[i][j];
+                               }
+                       }
+
+                       weight = 1 / weight;
+
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+
+                       mul *= weight;
+                       mulOther *= weight;
+
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+
+                               var nextY = (y == h) ? y - 1 : y;
+                               var prevY = (y == 1) ? 0 : y-2;
+
+                               var offsetYPrev = prevY*w4;
+                               var offsetYNext = nextY*w4;
+
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
+                                       var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
+
+                                       var r = ((
+                                               - dataCopy[offsetPrev]
+                                               - dataCopy[offset-4]
+                                               - dataCopy[offset+4]
+                                               - dataCopy[offsetNext])         * mulOther
+                                               + dataCopy[offset]      * mul
+                                               );
+
+                                       var g = ((
+                                               - dataCopy[offsetPrev+1]
+                                               - dataCopy[offset-3]
+                                               - dataCopy[offset+5]
+                                               - dataCopy[offsetNext+1])       * mulOther
+                                               + dataCopy[offset+1]    * mul
+                                               );
+
+                                       var b = ((
+                                               - dataCopy[offsetPrev+2]
+                                               - dataCopy[offset-2]
+                                               - dataCopy[offset+6]
+                                               - dataCopy[offsetNext+2])       * mulOther
+                                               + dataCopy[offset+2]    * mul
+                                               );
+
+
+                                       if (r < 0 ) r = 0;
+                                       if (g < 0 ) g = 0;
+                                       if (b < 0 ) b = 0;
+                                       if (r > 255 ) r = 255;
+                                       if (g > 255 ) g = 255;
+                                       if (b > 255 ) b = 255;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+/*
+ * Pixastic Lib - Solarize filter - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+Pixastic.Actions.solarize = {
+
+       process : function(params) {
+               var useAverage = !!(params.options.average && params.options.average != "false");
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var data = Pixastic.prepareData(params);
+                       var rect = params.options.rect;
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x-1)*4;
+
+                                       var r = data[offset];
+                                       var g = data[offset+1];
+                                       var b = data[offset+2];
+
+                                       if (r > 127) r = 255 - r;
+                                       if (g > 127) g = 255 - g;
+                                       if (b > 127) b = 255 - b;
+
+                                       data[offset] = r;
+                                       data[offset+1] = g;
+                                       data[offset+2] = b;
+
+                               } while (--x);
+                       } while (--y);
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return (Pixastic.Client.hasCanvasImageData());
+       }
+}/*
+ * Pixastic Lib - USM - v0.1.0
+ * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
+ * License: [http://www.pixastic.com/lib/license.txt]
+ */
+
+
+Pixastic.Actions.unsharpmask = {
+       process : function(params) {
+
+               var amount = (parseFloat(params.options.amount)||0);
+               var blurAmount = parseFloat(params.options.radius)||0;
+               var threshold = parseFloat(params.options.threshold)||0;
+
+               amount = Math.min(500,Math.max(0,amount)) / 2;
+               blurAmount = Math.min(5,Math.max(0,blurAmount)) / 10;
+               threshold = Math.min(255,Math.max(0,threshold));
+
+               threshold--;
+               var thresholdNeg = -threshold;
+
+               amount *= 0.016;
+               amount++;
+
+               if (Pixastic.Client.hasCanvasImageData()) {
+                       var rect = params.options.rect;
+
+                       var blurCanvas = document.createElement("canvas");
+                       blurCanvas.width = params.width;
+                       blurCanvas.height = params.height;
+                       var blurCtx = blurCanvas.getContext("2d");
+                       blurCtx.drawImage(params.canvas,0,0);
+
+                       var scale = 2;
+                       var smallWidth = Math.round(params.width / scale);
+                       var smallHeight = Math.round(params.height / scale);
+
+                       var copy = document.createElement("canvas");
+                       copy.width = smallWidth;
+                       copy.height = smallHeight;
+
+                       var steps = Math.round(blurAmount * 20);
+
+                       var copyCtx = copy.getContext("2d");
+                       for (var i=0;i<steps;i++) {
+                               var scaledWidth = Math.max(1,Math.round(smallWidth - i));
+                               var scaledHeight = Math.max(1,Math.round(smallHeight - i));
+
+                               copyCtx.clearRect(0,0,smallWidth,smallHeight);
+
+                               copyCtx.drawImage(
+                                       blurCanvas,
+                                       0,0,params.width,params.height,
+                                       0,0,scaledWidth,scaledHeight
+                               );
+       
+                               blurCtx.clearRect(0,0,params.width,params.height);
+       
+                               blurCtx.drawImage(
+                                       copy,
+                                       0,0,scaledWidth,scaledHeight,
+                                       0,0,params.width,params.height
+                               );
+                       }
+
+                       var data = Pixastic.prepareData(params);
+                       var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});
+                       var w = rect.width;
+                       var h = rect.height;
+                       var w4 = w*4;
+                       var y = h;
+                       do {
+                               var offsetY = (y-1)*w4;
+                               var x = w;
+                               do {
+                                       var offset = offsetY + (x*4-4);
+
+                                       var difR = data[offset] - blurData[offset];
+                                       if (difR > threshold || difR < thresholdNeg) {
+                                               var blurR = blurData[offset];
+                                               blurR = amount * difR + blurR;
+                                               data[offset] = blurR > 255 ? 255 : (blurR < 0 ? 0 : blurR);
+                                       }
+
+                                       var difG = data[offset+1] - blurData[offset+1];
+                                       if (difG > threshold || difG < thresholdNeg) {
+                                               var blurG = blurData[offset+1];
+                                               blurG = amount * difG + blurG;
+                                               data[offset+1] = blurG > 255 ? 255 : (blurG < 0 ? 0 : blurG);
+                                       }
+
+                                       var difB = data[offset+2] - blurData[offset+2];
+                                       if (difB > threshold || difB < thresholdNeg) {
+                                               var blurB = blurData[offset+2];
+                                               blurB = amount * difB + blurB;
+                                               data[offset+2] = blurB > 255 ? 255 : (blurB < 0 ? 0 : blurB);
+                                       }
+
+                               } while (--x);
+                       } while (--y);
+
+                       return true;
+               }
+       },
+       checkSupport : function() {
+               return Pixastic.Client.hasCanvasImageData();
+       }
+}
+
+
+
+
index a487ba2..bda133c 100644 (file)
-/* http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/ */\r
-\r
-html, body, div, span, applet, object, iframe,\r
-h1, h2, h3, h4, h5, h6, p, blockquote, pre,\r
-a, abbr, acronym, address, big, cite, code,\r
-del, dfn, em, font, img, ins, kbd, q, s, samp,\r
-small, strike, strong, sub, sup, tt, var,\r
-dl, dt, dd, ol, ul, li,\r
-fieldset, form, label, legend,\r
-table, caption, tbody, tfoot, thead, tr, th, td {\r
-       margin: 0;\r
-       padding: 0;\r
-       border: 0;\r
-       outline: 0;\r
-       font-weight: inherit;\r
-       font-style: inherit;\r
-       font-size: 100%;\r
-       font-family: inherit;\r
-       vertical-align: baseline;\r
-}\r
-/* remember to define focus styles! */\r
-:focus {\r
-       outline: 0;\r
-}\r
-body {\r
-       line-height: 1;\r
-       color: black;\r
-       background: white;\r
-}\r
-ol, ul {\r
-       list-style: none;\r
-}\r
-/* tables still need 'cellspacing="0"' in the markup */\r
-table {\r
-       border-collapse: separate;\r
-       border-spacing: 0;\r
-}\r
-caption, th, td {\r
-       text-align: left;\r
-       font-weight: normal;\r
-}\r
-blockquote:before, blockquote:after,\r
-q:before, q:after {\r
-       content: "";\r
-}\r
-blockquote, q {\r
-       quotes: "" "";\r
-}\r
-/* end reset */\r
-\r
-/* -----------------------\r
- *   Base\r
- * -----------------------\r
- */\r
-\r
-/* main container element for editor app */\r
-#pixastic-editor {\r
-       margin : 0;\r
-       position : absolute;\r
-       left : 0;\r
-       top : 0;\r
-       padding: 0px;\r
-       width: 100%;\r
-       height: 100%;\r
-       font-family : Helvetica,Arial,sans-serif;\r
-       overflow : hidden;\r
-       z-index : 10000000;\r
-} \r
-\r
-\r
-/* -----------------------\r
- *   Loading screen\r
- * -----------------------\r
- */\r
-\r
-/* container for loading screen */\r
-#loading-screen {\r
-       margin : 0;\r
-       position : absolute;\r
-       left : 0;\r
-       top : 0;\r
-       padding: 0px;\r
-       width: 100%;\r
-       height: 100%;\r
-       font-family : Helvetica,Arial,sans-serif;\r
-       overflow : hidden;\r
-       z-index : 10000000;\r
-       background-color : #111;\r
-       opacity : 0.9;\r
-       display : table;\r
-       text-align : center;\r
-} \r
-\r
-/* container for spinner in loading screen */\r
-#loading-screen-cell {\r
-       display : table-cell;\r
-       vertical-align : middle;\r
-       text-align : center;\r
-}\r
-\r
-\r
-/* -----------------------\r
- *   Misc\r
- * -----------------------\r
- */\r
-\r
-\r
-// UI error dialog\r
-.ui-dialog .error-dialog {\r
-       background-color : #544;\r
-}\r
-\r
-/* loading spinner */\r
-.spinner {\r
-       width : 31px;\r
-       height : 31px;\r
-       display : inline-block;\r
-       background: url(spinner.gif);\r
-       overflow : hidden;\r
-}\r
-\r
-canvas.display-canvas,\r
-canvas.undo-canvas {\r
-       /*\r
-       background : url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC1JREFUeNpiPHPmDAM2YGxsjFWciYFEMKqBGMD4//9/rBJnz54dDSX6aQAIMABCtQiAsDRF+wAAAABJRU5ErkJggg==');\r
-       */\r
-       background : url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC5JREFUeNpiPHPmTAMDHmBsbIxPmoGJgUIwasBgMICFUDyfPXt2NBCHvwEAAQYAICIGn294LYEAAAAASUVORK5CYII=');\r
-\r
-}\r
-\r
-.far-far-away {\r
-       position : absolute;\r
-       left : -9999px;\r
-       top : -9999px;\r
-}\r
-\r
-#powered-by-pixastic {\r
-       position : absolute;\r
-       bottom : 0px;\r
-       margin-bottom : 23px;\r
-       margin-left : 42px;\r
-}\r
-#powered-by-pixastic a {\r
-       font-size : 12px;\r
-       font-family : Helvetica,Arial,sans-serif;\r
-       letter-spacing : 0.1em;\r
-       color : rgb(100,100,100);\r
-       color : rgba(255,255,255,0.2);\r
-       text-decoration : none;\r
-}\r
-\r
-#powered-by-pixastic a:hover {\r
-       color : rgb(200,200,200);\r
-       color : rgba(255,255,255,0.7);\r
-       text-decoration : underline;\r
-}\r
-\r
-\r
-/* -----------------------\r
- *   Skeleton structure\r
- * -----------------------\r
- */\r
-\r
-/* editor background underlay */\r
-#background {\r
-       background-color : #111;\r
-       opacity : 0.9;\r
-       width : 100%;\r
-       height : 100%;\r
-       position : absolute;\r
-       z-index : -1;\r
-}\r
-\r
-#image-area {\r
-       position : relative;\r
-       background-color : #222;\r
-       border : 1px solid #444;\r
-       width : 100%;\r
-       height : 100%;\r
-       -moz-box-sizing:border-box;\r
-       overflow : auto;\r
-       text-align : center;\r
-}\r
-\r
-#image-area-sub {\r
-}\r
-\r
-#image-container {\r
-}\r
-\r
-#image-overlay-container {\r
-       -moz-box-sizing:border-box;\r
-       width:100%;\r
-       height:100%;\r
-       position:absolute;\r
-       top:0;\r
-       left:0;\r
-}\r
-\r
-#image-overlay {\r
-}\r
-\r
-\r
-/* structure elements */\r
-#edit-ctr-1 {\r
-       position : absolute;\r
-       top : 0;\r
-       left : 0;\r
-       width : 100%;\r
-       height : 100%;\r
-}\r
-\r
-#edit-ctr-2 {\r
-       -moz-box-sizing : border-box;\r
-       box-sizing : border-box;\r
-       padding-left:40px;\r
-       padding-right:420px;\r
-       padding-top:70px;\r
-       padding-bottom : 40px;\r
-       height : 100%;\r
-       width : 100%;\r
-}\r
-\r
-\r
-/* main menu bar */\r
-#main-bar {\r
-       position : absolute;\r
-       width : 100%;\r
-       text-align : right;\r
-       margin-top : 20px;\r
-       margin-right : 30px;\r
-}\r
-\r
-/* area on the right with accordion widgets and undo bar */\r
-#controls-bar {\r
-       margin-right : -385px;\r
-       width : 372px;\r
-       float : right;\r
-       height : 100%;\r
-}\r
-\r
-/* accordion area */\r
-#action-bar {\r
-       padding : 10px;\r
-       width : 290px;\r
-       background-color : #222;\r
-       border : 1px solid #444;\r
-       -moz-box-sizing : border-box;\r
-       box-sizing : border-box;\r
-       height : 100%;\r
-       overflow-x : hidden;\r
-       overflow-y : auto;\r
-       float: right; \r
-       position : relative;\r
-}\r
-\r
-#action-bar-overlay {\r
-       position : absolute;\r
-       z-index : 1000000;\r
-       width : 100%;\r
-       height : 100%;\r
-       left : 0;\r
-       top : 0;\r
-       background-color : #444;\r
-       opacity : 0.2;\r
-       display : none;\r
-}\r
-\r
-\r
-/* vertical bar with undo image states */\r
-#undo-bar {\r
-       -moz-box-sizing : border-box;\r
-       box-sizing : border-box;\r
-       background-color : #222;\r
-       border : 1px solid #444;\r
-       width: 70px; \r
-       height: 100%;\r
-       overflow: hidden;\r
-       padding-top : 3px;\r
-}\r
-\r
-\r
-\r
-/* -----------------------\r
- *   Main menu styles\r
- * -----------------------\r
- */\r
-\r
-.main-tab {\r
-       color : #999;\r
-       display : inline-block;\r
-       width : 150px;\r
-       text-transform : lowercase;\r
-       font-size : 22px;\r
-       cursor : pointer;\r
-       text-align : center;\r
-       text-decoration : none;\r
-       padding-top : 4px;\r
-       padding-bottom : 5px;\r
-       outline : 0;\r
-}\r
-\r
-.main-tab.hover {\r
-       color : white !important;\r
-}\r
-\r
-.main-tab.active {\r
-       color : white;\r
-}\r
-\r
-\r
-\r
-/* -----------------------\r
- *   Undo list\r
- * -----------------------\r
- */\r
-\r
-\r
-.undo-canvas-small {\r
-       width : 60px;\r
-       height : 40px;\r
-       cursor : pointer;\r
-}\r
-\r
-.undo-link {\r
-       width : 60px;\r
-       height : 40px;\r
-       display : block;\r
-       margin : 4px;\r
-       cursor : pointer;\r
-       opacity : 0.8;\r
-}\r
-\r
-.undo-link.hover {\r
-       opacity : 1;\r
-}\r
-\r
-\r
-\r
-/* -----------------------\r
- *   Action UI controls\r
- * -----------------------\r
- */\r
-\r
-\r
-.ui-slider-label, \r
-.ui-checkbox-label, \r
-.ui-textinput-label, \r
-.ui-select-label {\r
-       width : 70px;\r
-       text-align : right;\r
-       margin-right : 5px;\r
-       display : inline-block;\r
-}\r
-\r
-.ui-textinput-label-right {\r
-       margin-left : 5px;\r
-}\r
-\r
-.ui-textinput {\r
-}\r
-\r
-.ui-numericinput {\r
-       width : 35px;\r
-}\r
-\r
-.ui-slider {\r
-       width : 125px;\r
-       display : inline-block;\r
-       margin-left : 3px;\r
-       background-color : #222;\r
-}\r
-\r
-.ui-slider-value {\r
-       font-size : 11px;\r
-       width : 25px;\r
-       display : inline-block;\r
-       margin-left : 10px;\r
-}\r
-\r
-.ui-action-output {\r
-       margin-bottom : 10px;\r
-}\r
-\r
-.ui-accordion .ui-accordion-content-active {\r
-       font-size : 11px;\r
-       overflow : hidden;\r
-}\r
-\r
-.ui-slider-horizontal {\r
-}\r
-\r
-.ui-slider-container, \r
-.ui-checkbox-container, \r
-.ui-textinput-container, \r
-.ui-select-container {\r
-       margin-top : 0px;\r
-       margin-bottom : 10px;\r
-       white-space : nowrap;\r
-}\r
-\r
-.ui-preview-checkbox-container {\r
-       display : inline-block;\r
-}\r
-\r
-.ui-checkbox {\r
-       margin-bottom:3px;\r
-       margin-left:5px;\r
-       margin-right:5px;\r
-       margin-top:0px;\r
-       vertical-align:middle;\r
-}\r
-\r
-input::-moz-focus-inner { border: 0; }\r
-\r
-.action-output-text {\r
-       margin-bottom : 5px;\r
-}\r
-\r
-button {\r
-       margin-right : 5px;\r
-}\r
-\r
+/* http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/ */
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, font, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td {
+       margin: 0;
+       padding: 0;
+       border: 0;
+       outline: 0;
+       font-weight: inherit;
+       font-style: inherit;
+       font-size: 100%;
+       font-family: inherit;
+       vertical-align: baseline;
+}
+/* remember to define focus styles! */
+:focus {
+       outline: 0;
+}
+body {
+       line-height: 1;
+       color: black;
+       background: white;
+}
+ol, ul {
+       list-style: none;
+}
+/* tables still need 'cellspacing="0"' in the markup */
+table {
+       border-collapse: separate;
+       border-spacing: 0;
+}
+caption, th, td {
+       text-align: left;
+       font-weight: normal;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+       content: "";
+}
+blockquote, q {
+       quotes: "" "";
+}
+/* end reset */
+
+/* -----------------------
+ *   Base
+ * -----------------------
+ */
+
+/* main container element for editor app */
+#pixastic-editor {
+       margin : 0;
+       position : absolute;
+       left : 0;
+       top : 0;
+       padding: 0px;
+       width: 100%;
+       height: 100%;
+       font-family : Helvetica,Arial,sans-serif;
+       overflow : hidden;
+       z-index : 10000000;
+} 
+
+
+/* -----------------------
+ *   Loading screen
+ * -----------------------
+ */
+
+/* container for loading screen */
+#loading-screen {
+       margin : 0;
+       position : absolute;
+       left : 0;
+       top : 0;
+       padding: 0px;
+       width: 100%;
+       height: 100%;
+       font-family : Helvetica,Arial,sans-serif;
+       overflow : hidden;
+       z-index : 10000000;
+       background-color : #111;
+       opacity : 0.9;
+       display : table;
+       text-align : center;
+} 
+
+/* container for spinner in loading screen */
+#loading-screen-cell {
+       display : table-cell;
+       vertical-align : middle;
+       text-align : center;
+}
+
+
+/* -----------------------
+ *   Misc
+ * -----------------------
+ */
+
+
+// UI error dialog
+.ui-dialog .error-dialog {
+       background-color : #544;
+}
+
+/* loading spinner */
+.spinner {
+       width : 31px;
+       height : 31px;
+       display : inline-block;
+       background: url(spinner.gif);
+       overflow : hidden;
+}
+
+canvas.display-canvas,
+canvas.undo-canvas {
+       /*
+       background : url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC1JREFUeNpiPHPmDAM2YGxsjFWciYFEMKqBGMD4//9/rBJnz54dDSX6aQAIMABCtQiAsDRF+wAAAABJRU5ErkJggg==');
+       */
+       background : url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAC5JREFUeNpiPHPmTAMDHmBsbIxPmoGJgUIwasBgMICFUDyfPXt2NBCHvwEAAQYAICIGn294LYEAAAAASUVORK5CYII=');
+
+}
+
+.far-far-away {
+       position : absolute;
+       left : -9999px;
+       top : -9999px;
+}
+
+#powered-by-pixastic {
+       position : absolute;
+       bottom : 0px;
+       margin-bottom : 23px;
+       margin-left : 42px;
+}
+#powered-by-pixastic a {
+       font-size : 12px;
+       font-family : Helvetica,Arial,sans-serif;
+       letter-spacing : 0.1em;
+       color : rgb(100,100,100);
+       color : rgba(255,255,255,0.2);
+       text-decoration : none;
+}
+
+#powered-by-pixastic a:hover {
+       color : rgb(200,200,200);
+       color : rgba(255,255,255,0.7);
+       text-decoration : underline;
+}
+
+
+/* -----------------------
+ *   Skeleton structure
+ * -----------------------
+ */
+
+/* editor background underlay */
+#background {
+       background-color : #111;
+       opacity : 0.9;
+       width : 100%;
+       height : 100%;
+       position : absolute;
+       z-index : -1;
+}
+
+#image-area {
+       position : relative;
+       background-color : #222;
+       border : 1px solid #444;
+       width : 100%;
+       height : 100%;
+       -moz-box-sizing:border-box;
+       overflow : auto;
+       text-align : center;
+}
+
+#image-area-sub {
+}
+
+#image-container {
+}
+
+#image-overlay-container {
+       -moz-box-sizing:border-box;
+       width:100%;
+       height:100%;
+       position:absolute;
+       top:0;
+       left:0;
+}
+
+#image-overlay {
+}
+
+
+/* structure elements */
+#edit-ctr-1 {
+       position : absolute;
+       top : 0;
+       left : 0;
+       width : 100%;
+       height : 100%;
+}
+
+#edit-ctr-2 {
+       -moz-box-sizing : border-box;
+       box-sizing : border-box;
+       padding-left:40px;
+       padding-right:420px;
+       padding-top:70px;
+       padding-bottom : 40px;
+       height : 100%;
+       width : 100%;
+}
+
+
+/* main menu bar */
+#main-bar {
+       position : absolute;
+       width : 100%;
+       text-align : right;
+       margin-top : 20px;
+       margin-right : 30px;
+}
+
+/* area on the right with accordion widgets and undo bar */
+#controls-bar {
+       margin-right : -385px;
+       width : 372px;
+       float : right;
+       height : 100%;
+}
+
+/* accordion area */
+#action-bar {
+       padding : 10px;
+       width : 290px;
+       background-color : #222;
+       border : 1px solid #444;
+       -moz-box-sizing : border-box;
+       box-sizing : border-box;
+       height : 100%;
+       overflow-x : hidden;
+       overflow-y : auto;
+       float: right; 
+       position : relative;
+}
+
+#action-bar-overlay {
+       position : absolute;
+       z-index : 1000000;
+       width : 100%;
+       height : 100%;
+       left : 0;
+       top : 0;
+       background-color : #444;
+       opacity : 0.2;
+       display : none;
+}
+
+
+/* vertical bar with undo image states */
+#undo-bar {
+       -moz-box-sizing : border-box;
+       box-sizing : border-box;
+       background-color : #222;
+       border : 1px solid #444;
+       width: 70px; 
+       height: 100%;
+       overflow: hidden;
+       padding-top : 3px;
+}
+
+
+
+/* -----------------------
+ *   Main menu styles
+ * -----------------------
+ */
+
+.main-tab {
+       color : #999;
+       display : inline-block;
+       width : 150px;
+       text-transform : lowercase;
+       font-size : 22px;
+       cursor : pointer;
+       text-align : center;
+       text-decoration : none;
+       padding-top : 4px;
+       padding-bottom : 5px;
+       outline : 0;
+}
+
+.main-tab.hover {
+       color : white !important;
+}
+
+.main-tab.active {
+       color : white;
+}
+
+
+
+/* -----------------------
+ *   Undo list
+ * -----------------------
+ */
+
+
+.undo-canvas-small {
+       width : 60px;
+       height : 40px;
+       cursor : pointer;
+}
+
+.undo-link {
+       width : 60px;
+       height : 40px;
+       display : block;
+       margin : 4px;
+       cursor : pointer;
+       opacity : 0.8;
+}
+
+.undo-link.hover {
+       opacity : 1;
+}
+
+
+
+/* -----------------------
+ *   Action UI controls
+ * -----------------------
+ */
+
+
+.ui-slider-label, 
+.ui-checkbox-label, 
+.ui-textinput-label, 
+.ui-select-label {
+       width : 70px;
+       text-align : right;
+       margin-right : 5px;
+       display : inline-block;
+}
+
+.ui-textinput-label-right {
+       margin-left : 5px;
+}
+
+.ui-textinput {
+}
+
+.ui-numericinput {
+       width : 35px;
+}
+
+.ui-slider {
+       width : 125px;
+       display : inline-block;
+       margin-left : 3px;
+       background-color : #222;
+}
+
+.ui-slider-value {
+       font-size : 11px;
+       width : 25px;
+       display : inline-block;
+       margin-left : 10px;
+}
+
+.ui-action-output {
+       margin-bottom : 10px;
+}
+
+.ui-accordion .ui-accordion-content-active {
+       font-size : 11px;
+       overflow : hidden;
+}
+
+.ui-slider-horizontal {
+}
+
+.ui-slider-container, 
+.ui-checkbox-container, 
+.ui-textinput-container, 
+.ui-select-container {
+       margin-top : 0px;
+       margin-bottom : 10px;
+       white-space : nowrap;
+}
+
+.ui-preview-checkbox-container {
+       display : inline-block;
+}
+
+.ui-checkbox {
+       margin-bottom:3px;
+       margin-left:5px;
+       margin-right:5px;
+       margin-top:0px;
+       vertical-align:middle;
+}
+
+input::-moz-focus-inner { border: 0; }
+
+.action-output-text {
+       margin-bottom : 5px;
+}
+
+button {
+       margin-right : 5px;
+}
+
index a0a20ba..6b267ac 100644 (file)
-(function($) {\r
-\r
-       var PE = PixasticEditor;\r
-\r
-       function makeSlider(label, id, min, max, step, defaultVal, onChange) {\r
-               var $ctr = $j("<div></div>", PE.getDocument())\r
-                       .addClass("ui-slider-container");\r
-\r
-               var $label = $j("<label></label>", PE.getDocument())\r
-                       .addClass("ui-slider-label")\r
-                       .attr("for", "input-slider-" + id)\r
-                       .html(label + ":")\r
-                       .appendTo($ctr);\r
-\r
-               var $value = $j("<div></div>", PE.getDocument())\r
-                       .addClass("ui-slider-value")\r
-                       .html(defaultVal());\r
-\r
-               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
-                       .attr("id", "input-hidden-" + id)\r
-                       .val(defaultVal())\r
-                       .appendTo($ctr);\r
-\r
-               var performOnChange = true;\r
-\r
-               var $slider = $j("<div class='ui-slider'><div class='ui-slider-handle'></div><div class='ui-slider-range'></div></div>", PE.getDocument())\r
-                       .appendTo($ctr)\r
-                       .attr("id", "input-slider-" + id)\r
-                       .slider({\r
-                               slide: function() {\r
-                                       $value.html($j(this).slider("value"));\r
-                                       $valueField.val($j(this).slider("value"));\r
-                               },\r
-                               change : function() {\r
-                                       $value.html($j(this).slider("value"));\r
-                                       $valueField.val($j(this).slider("value"));\r
-                                       if (onChange && performOnChange)\r
-                                               onChange();\r
-                               },\r
-                               min : min,\r
-                               max : max,\r
-                               step : step,\r
-                               value : defaultVal()\r
-                       });\r
-\r
-               $value.appendTo($ctr);\r
-\r
-               return {\r
-                       container : $ctr,\r
-                       label : $label,\r
-                       slider : $slider,\r
-                       valueText : $value,\r
-                       valueField : $valueField,\r
-                       reset : function() {\r
-                               performOnChange = false;\r
-                               $value.html(defaultVal());\r
-                               $valueField.val(defaultVal());\r
-                               $slider.slider("value", defaultVal());\r
-                               performOnChange = true;\r
-                       }\r
-               };\r
-       }\r
-\r
-       function makeCheckbox(label, id, defaultVal, onChange) {\r
-               var $ctr = $j("<div></div>", PE.getDocument())\r
-                       .addClass("ui-checkbox-container");\r
-\r
-               var $label = $j("<label></label>", PE.getDocument())\r
-                       .addClass("ui-checkbox-label")\r
-                       .attr("for", "input-checkbox-" + id)\r
-                       .html(label + ":")\r
-                       .appendTo($ctr);\r
-\r
-               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
-                       .attr("id", "input-hidden-" + id)\r
-                       .val(defaultVal())\r
-                       .appendTo($ctr);\r
-\r
-               var performOnChange = true;\r
-\r
-               var $checkbox = $j("<input type=\"checkbox\"></input>", PE.getDocument())\r
-                       .addClass("ui-checkbox")\r
-                       .attr("id", "input-checkbox-" + id)\r
-                       .attr("checked", defaultVal())\r
-                       .appendTo($ctr)\r
-                       .change(function() {\r
-                               $valueField.val(this.checked);\r
-                               if (onChange && performOnChange)\r
-                                       onChange();\r
-                       });\r
-\r
-               return {\r
-                       container : $ctr,\r
-                       label : $label,\r
-                       checkbox : $checkbox,\r
-                       valueField : $valueField,\r
-                       reset : function() {\r
-                               performOnChange = false;\r
-                               $checkbox.attr("checked", defaultVal());\r
-                               $valueField.val(defaultVal());\r
-                               performOnChange = true;\r
-                       }\r
-               };\r
-       }\r
-\r
-       function makeSelect(label, id, values, defaultVal, onChange) {\r
-               var $ctr = $j("<div></div>", PE.getDocument())\r
-                       .addClass("ui-select-container");\r
-\r
-               var $label = $j("<label></label>", PE.getDocument())\r
-                       .addClass("ui-checkbox-label")\r
-                       .attr("for", "input-checkbox-" + id)\r
-                       .html(label + ":")\r
-                       .appendTo($ctr);\r
-\r
-               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
-                       .attr("id", "input-hidden-" + id)\r
-                       .val(defaultVal())\r
-                       .appendTo($ctr);\r
-\r
-               var selectHtml = "<select>";\r
-               for (var i=0;i<values.length;i++) {\r
-                       selectHtml += "<option value='" + values[i].value + "' " \r
-                               + (defaultVal() == values[i].value ? "selected" : "") \r
-                               + ">" + values[i].name + "</option>";\r
-               }\r
-               selectHtml += "</select>";\r
-\r
-               var $select = $j(selectHtml).appendTo($ctr);\r
-\r
-               var performOnChange = true;\r
-\r
-               $select.change(\r
-                       function() {\r
-                               $valueField.val(this.options[this.selectedIndex].value);\r
-                               if (onChange && performOnChange)\r
-                                       onChange();\r
-                       }\r
-               );\r
-\r
-               return {\r
-                       container : $ctr,\r
-                       label : $label,\r
-                       select : $select,\r
-                       valueField : $valueField,\r
-                       reset : function() {\r
-                               performOnChange = false;\r
-                               var defVal = defaultVal();\r
-                               $select.val(defVal);\r
-                               $valueField.val(defVal);\r
-                               performOnChange = true;\r
-                       }\r
-               };\r
-       }\r
-\r
-       function makeNumericInput(label, labelRight, id, min, max, step, defaultVal, onChange) {\r
-               var $ctr = $j("<div></div>", PE.getDocument())\r
-                       .addClass("ui-textinput-container");\r
-\r
-               var $label = $j("<label></label>", PE.getDocument())\r
-                       .addClass("ui-textinput-label")\r
-                       .attr("for", "input-numeric-" + id)\r
-                       .html(label + ":")\r
-                       .appendTo($ctr);\r
-\r
-               var $valueField = $j("<input type='hidden'>", PE.getDocument())\r
-                       .attr("id", "input-hidden-" + id)\r
-                       .val(defaultVal())\r
-                       .appendTo($ctr);\r
-\r
-               var performOnChange = true;\r
-\r
-               function setVal(val) {\r
-                       val = Math.min(max, val);\r
-                       val = Math.max(min, val);\r
-                       $textInput.val(val);\r
-                       $valueField.val(val);\r
-               }\r
-\r
-               var $textInput = $j("<input type=\"text\"></input>", PE.getDocument())\r
-                       .addClass("ui-textinput")\r
-                       .addClass("ui-numericinput")\r
-                       .appendTo($ctr)\r
-                       .val(defaultVal())\r
-                       .attr("id", "input-numeric-" + id)\r
-                       .change(function() {\r
-                               var val = parseFloat(this.value);\r
-                               setVal(val);\r
-                               if (onChange && performOnChange)\r
-                                       onChange();\r
-                       })\r
-                       .keydown(function(e) {\r
-                               var val = parseFloat($j(this).val());\r
-                               if (e.keyCode == 38) { // up\r
-                                       setVal(val + step);\r
-                               }\r
-                               if (e.keyCode == 40) { // down\r
-                                       setVal(val - step);\r
-                               }\r
-                       });\r
-\r
-               if (labelRight) {\r
-                       var $labelRight = $j("<label></label>", PE.getDocument())\r
-                               .addClass("ui-textinput-label-right")\r
-                               .html(labelRight)\r
-                               .appendTo($ctr);\r
-               }\r
-\r
-               return {\r
-                       container : $ctr,\r
-                       label : $label,\r
-                       textinput : $textInput,\r
-                       valueField : $valueField,\r
-                       reset : function() {\r
-                               performOnChange = false;\r
-                               setVal(defaultVal());\r
-                               performOnChange = true;\r
-                       }\r
-               };\r
-       }\r
-\r
-       function makeButton(text) {\r
-               var $button = $j("<button></button>", PE.getDocument()).html(text);\r
-               return $button;\r
-       }\r
-\r
-\r
-       PE.UI = {\r
-               makeSlider : makeSlider,\r
-               makeCheckbox : makeCheckbox,\r
-               makeNumericInput : makeNumericInput,\r
-               makeSelect : makeSelect,\r
-               makeButton : makeButton\r
-       }\r
-\r
-})(PixasticEditor.jQuery);\r
-\r
+(function($) {
+
+       var PE = PixasticEditor;
+
+       function makeSlider(label, id, min, max, step, defaultVal, onChange) {
+               var $ctr = $j("<div></div>", PE.getDocument())
+                       .addClass("ui-slider-container");
+
+               var $label = $j("<label></label>", PE.getDocument())
+                       .addClass("ui-slider-label")
+                       .attr("for", "input-slider-" + id)
+                       .html(label + ":")
+                       .appendTo($ctr);
+
+               var $value = $j("<div></div>", PE.getDocument())
+                       .addClass("ui-slider-value")
+                       .html(defaultVal());
+
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())
+                       .attr("id", "input-hidden-" + id)
+                       .val(defaultVal())
+                       .appendTo($ctr);
+
+               var performOnChange = true;
+
+               var $slider = $j("<div class='ui-slider'><div class='ui-slider-handle'></div><div class='ui-slider-range'></div></div>", PE.getDocument())
+                       .appendTo($ctr)
+                       .attr("id", "input-slider-" + id)
+                       .slider({
+                               slide: function() {
+                                       $value.html($j(this).slider("value"));
+                                       $valueField.val($j(this).slider("value"));
+                               },
+                               change : function() {
+                                       $value.html($j(this).slider("value"));
+                                       $valueField.val($j(this).slider("value"));
+                                       if (onChange && performOnChange)
+                                               onChange();
+                               },
+                               min : min,
+                               max : max,
+                               step : step,
+                               value : defaultVal()
+                       });
+
+               $value.appendTo($ctr);
+
+               return {
+                       container : $ctr,
+                       label : $label,
+                       slider : $slider,
+                       valueText : $value,
+                       valueField : $valueField,
+                       reset : function() {
+                               performOnChange = false;
+                               $value.html(defaultVal());
+                               $valueField.val(defaultVal());
+                               $slider.slider("value", defaultVal());
+                               performOnChange = true;
+                       }
+               };
+       }
+
+       function makeCheckbox(label, id, defaultVal, onChange) {
+               var $ctr = $j("<div></div>", PE.getDocument())
+                       .addClass("ui-checkbox-container");
+
+               var $label = $j("<label></label>", PE.getDocument())
+                       .addClass("ui-checkbox-label")
+                       .attr("for", "input-checkbox-" + id)
+                       .html(label + ":")
+                       .appendTo($ctr);
+
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())
+                       .attr("id", "input-hidden-" + id)
+                       .val(defaultVal())
+                       .appendTo($ctr);
+
+               var performOnChange = true;
+
+               var $checkbox = $j("<input type=\"checkbox\"></input>", PE.getDocument())
+                       .addClass("ui-checkbox")
+                       .attr("id", "input-checkbox-" + id)
+                       .attr("checked", defaultVal())
+                       .appendTo($ctr)
+                       .change(function() {
+                               $valueField.val(this.checked);
+                               if (onChange && performOnChange)
+                                       onChange();
+                       });
+
+               return {
+                       container : $ctr,
+                       label : $label,
+                       checkbox : $checkbox,
+                       valueField : $valueField,
+                       reset : function() {
+                               performOnChange = false;
+                               $checkbox.attr("checked", defaultVal());
+                               $valueField.val(defaultVal());
+                               performOnChange = true;
+                       }
+               };
+       }
+
+       function makeSelect(label, id, values, defaultVal, onChange) {
+               var $ctr = $j("<div></div>", PE.getDocument())
+                       .addClass("ui-select-container");
+
+               var $label = $j("<label></label>", PE.getDocument())
+                       .addClass("ui-checkbox-label")
+                       .attr("for", "input-checkbox-" + id)
+                       .html(label + ":")
+                       .appendTo($ctr);
+
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())
+                       .attr("id", "input-hidden-" + id)
+                       .val(defaultVal())
+                       .appendTo($ctr);
+
+               var selectHtml = "<select>";
+               for (var i=0;i<values.length;i++) {
+                       selectHtml += "<option value='" + values[i].value + "' " 
+                               + (defaultVal() == values[i].value ? "selected" : "") 
+                               + ">" + values[i].name + "</option>";
+               }
+               selectHtml += "</select>";
+
+               var $select = $j(selectHtml).appendTo($ctr);
+
+               var performOnChange = true;
+
+               $select.change(
+                       function() {
+                               $valueField.val(this.options[this.selectedIndex].value);
+                               if (onChange && performOnChange)
+                                       onChange();
+                       }
+               );
+
+               return {
+                       container : $ctr,
+                       label : $label,
+                       select : $select,
+                       valueField : $valueField,
+                       reset : function() {
+                               performOnChange = false;
+                               var defVal = defaultVal();
+                               $select.val(defVal);
+                               $valueField.val(defVal);
+                               performOnChange = true;
+                       }
+               };
+       }
+
+       function makeNumericInput(label, labelRight, id, min, max, step, defaultVal, onChange) {
+               var $ctr = $j("<div></div>", PE.getDocument())
+                       .addClass("ui-textinput-container");
+
+               var $label = $j("<label></label>", PE.getDocument())
+                       .addClass("ui-textinput-label")
+                       .attr("for", "input-numeric-" + id)
+                       .html(label + ":")
+                       .appendTo($ctr);
+
+               var $valueField = $j("<input type='hidden'>", PE.getDocument())
+                       .attr("id", "input-hidden-" + id)
+                       .val(defaultVal())
+                       .appendTo($ctr);
+
+               var performOnChange = true;
+
+               function setVal(val) {
+                       val = Math.min(max, val);
+                       val = Math.max(min, val);
+                       $textInput.val(val);
+                       $valueField.val(val);
+               }
+
+               var $textInput = $j("<input type=\"text\"></input>", PE.getDocument())
+                       .addClass("ui-textinput")
+                       .addClass("ui-numericinput")
+                       .appendTo($ctr)
+                       .val(defaultVal())
+                       .attr("id", "input-numeric-" + id)
+                       .change(function() {
+                               var val = parseFloat(this.value);
+                               setVal(val);
+                               if (onChange && performOnChange)
+                                       onChange();
+                       })
+                       .keydown(function(e) {
+                               var val = parseFloat($j(this).val());
+                               if (e.keyCode == 38) { // up
+                                       setVal(val + step);
+                               }
+                               if (e.keyCode == 40) { // down
+                                       setVal(val - step);
+                               }
+                       });
+
+               if (labelRight) {
+                       var $labelRight = $j("<label></label>", PE.getDocument())
+                               .addClass("ui-textinput-label-right")
+                               .html(labelRight)
+                               .appendTo($ctr);
+               }
+
+               return {
+                       container : $ctr,
+                       label : $label,
+                       textinput : $textInput,
+                       valueField : $valueField,
+                       reset : function() {
+                               performOnChange = false;
+                               setVal(defaultVal());
+                               performOnChange = true;
+                       }
+               };
+       }
+
+       function makeButton(text) {
+               var $button = $j("<button></button>", PE.getDocument()).html(text);
+               return $button;
+       }
+
+
+       PE.UI = {
+               makeSlider : makeSlider,
+               makeCheckbox : makeCheckbox,
+               makeNumericInput : makeNumericInput,
+               makeSelect : makeSelect,
+               makeButton : makeButton
+       }
+
+})(PixasticEditor.jQuery);
+
index 03f50b7..ef648f6 100644 (file)
-(function($) {\r
-\r
-var PE = PixasticEditor;\r
-\r
-PE.UI.data = {\r
-       tabs : [\r
-               {\r
-                       title : "Reshape",\r
-                       id : "reshape",\r
-                       actions : [\r
-                               {\r
-                                       title : "Resize",\r
-                                       id : "resize",\r
-                                       isAction : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Enter new dimensions below."\r
-                                               },\r
-                                               {\r
-                                                       label : "Width",\r
-                                                       labelRight : "px",\r
-                                                       option : "width",\r
-                                                       type : "number", \r
-                                                       range : [1,10000], \r
-                                                       step : 1,\r
-                                                       defaultValue : function() { return PE.getImageWidth(); },\r
-                                                       ui : "text"\r
-                                               },\r
-                                               {\r
-                                                       label : "Height",\r
-                                                       labelRight : "px",\r
-                                                       option : "height",\r
-                                                       type : "number", \r
-                                                       range : [1,10000], \r
-                                                       step : 1,\r
-                                                       defaultValue : function() { return PE.getImageHeight(); },\r
-                                                       ui : "text"\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Crop",\r
-                                       id : "crop",\r
-                                       isAction : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Enter new crop values below or use mouse to select crop area."\r
-                                               },\r
-                                               {\r
-                                                       label : "X",\r
-                                                       labelRight : "px",\r
-                                                       option : "left",\r
-                                                       type : "number", \r
-                                                       range : [0,10000], \r
-                                                       step : 1,\r
-                                                       defaultValue : 0,\r
-                                                       ui : "text"\r
-                                               },\r
-                                               {\r
-                                                       label : "Y",\r
-                                                       labelRight : "px",\r
-                                                       option : "top",\r
-                                                       type : "number", \r
-                                                       range : [0,10000], \r
-                                                       step : 1,\r
-                                                       defaultValue : 0,\r
-                                                       ui : "text"\r
-                                               },\r
-                                               {\r
-                                                       label : "Width",\r
-                                                       labelRight : "px",\r
-                                                       option : "width",\r
-                                                       type : "number", \r
-                                                       range : [1,10000], \r
-                                                       step : 1,\r
-                                                       defaultValue : function() { return PE.getImageWidth(); },\r
-                                                       ui : "text"\r
-                                               },\r
-                                               {\r
-                                                       label : "Height",\r
-                                                       labelRight : "px",\r
-                                                       option : "height",\r
-                                                       type : "number", \r
-                                                       range : [1,10000], \r
-                                                       step : 1,\r
-                                                       defaultValue : function() { return PE.getImageHeight(); },\r
-                                                       ui : "text"\r
-                                               }\r
-                                       ],\r
-                                       onactivate : function() {\r
-                                               var $canvas = PE.getDisplayCanvas();\r
-                                               var onchange = function(c) {\r
-                                                       var doc = PE.getDocument();\r
-                                                       $j("#input-numeric-crop-left", doc).val(c.x).change();\r
-                                                       $j("#input-numeric-crop-top", doc).val(c.y).change();\r
-                                                       $j("#input-numeric-crop-width", doc).val(c.w).change();\r
-                                                       $j("#input-numeric-crop-height", doc).val(c.h).change();\r
-                                                       $j("#input-hidden-crop-left", doc).val(c.x).change();\r
-                                                       $j("#input-hidden-crop-top", doc).val(c.y).change();\r
-                                                       $j("#input-hidden-crop-width", doc).val(c.w).change();\r
-                                                       $j("#input-hidden-crop-height", doc).val(c.h).change();\r
-                                               }\r
-                                               $canvas.data("Jcrop-onchange", onchange);\r
-                                               $canvas.Jcrop({onChange:onchange}, PE.getDocument());\r
-                                       },\r
-                                       ondeactivate : function() {\r
-                                               var $canvas = PE.getDisplayCanvas();\r
-                                               if ($canvas.data("Jcrop") && $canvas.data("Jcrop").destroy)\r
-                                                       $canvas.data("Jcrop").destroy();\r
-                                       },\r
-                                       onafteraction : function(action, isPreview) {\r
-                                               action.ondeactivate();\r
-                                               action.onactivate();\r
-                                               /*\r
-                                               var $canvas = PE.getDisplayCanvas();\r
-                                               if ($canvas.data("Jcrop") && $canvas.data("Jcrop").destroy)\r
-                                                       $canvas.data("Jcrop").destroy();\r
-                                               var onchange = $canvas.data("Jcrop-onchange");\r
-                                               $canvas.Jcrop({onChange:onchange});\r
-                                               */\r
-                                       }\r
-                               },\r
-                               {\r
-                                       title : "Rotate",\r
-                                       id : "rotate",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       forcePreview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Enter the angle (-180&deg; to 180&deg;) you want to rotate the picture. Use negative values for clockwise rotation, positive for counterclockwise."\r
-                                               },\r
-                                               {\r
-                                                       label : "Angle",\r
-                                                       labelRight : "&deg;",\r
-                                                       option : "angle",\r
-                                                       type : "number", \r
-                                                       range : [-180,180], \r
-                                                       step : 1,\r
-                                                       defaultValue : 0,\r
-                                                       ui : "text"\r
-                                               }\r
-                                       ],\r
-                                       onactivate : function() {\r
-                                               var doc = PE.getDocument();\r
-                                               var $displayCanvas = PE.getDisplayCanvas();\r
-                                               var dim = Math.min($displayCanvas.attr("height"), 200);\r
-                                               var $canvas = $j("<canvas></canvas>", doc);\r
-                                               PE.getOverlay().append($canvas);\r
-\r
-                                               $canvas.attr("width", dim);\r
-                                               $canvas.attr("height", dim);\r
-                                               $canvas.width(dim);\r
-                                               $canvas.height(dim);\r
-\r
-                                               $canvas.css("marginTop", (($displayCanvas.attr("height") - dim) * 0.5) + "px");\r
-\r
-                                               var lineWidth = 20;\r
-                                               var radius = dim/2 - lineWidth;\r
-                                               if (radius < 1) radius = 1;\r
-\r
-                                               var ctx = $canvas.get(0).getContext("2d");\r
-                                               ctx.beginPath()\r
-                                               ctx.arc(dim/2, dim/2, radius, 0, Math.PI*2, true);\r
-                                               ctx.closePath();\r
-                                               ctx.fillStyle = "rgba(200,200,200,0.2)";\r
-                                               ctx.fill();\r
-                                               ctx.strokeStyle = "rgba(200,200,200,0.5)";\r
-                                               ctx.lineWidth = 20;\r
-                                               ctx.stroke();\r
-\r
-                                               $j("#image-area", doc).css("cursor", "move");\r
-\r
-                                               $overlay = PE.getOverlay();\r
-\r
-                                               $canvas.get(0).ondragstart = function() {return false;}\r
-                                               $canvas.get(0).onselectstart = function() {return false;}\r
-\r
-                                               var mx = 0, my = 0;\r
-                                               var startMouseAngle = 0;\r
-                                               var startAngle = 0;\r
-                                               var deltaAngle = 0;\r
-                                               var angle = 0;\r
-\r
-                                               var mouseIsDown = false;\r
-                                               var onmousedown = function(e) {\r
-                                                       mouseIsDown = true;\r
-                                                       var offset = $displayCanvas.offset();\r
-                                                       mx = (e.pageX - offset.left) - $displayCanvas.attr("width")*0.5;\r
-                                                       my = (e.pageY - offset.top) - $displayCanvas.attr("height")*0.5;\r
-                                                       startMouseAngle = Math.atan2(my, mx);\r
-                                                       startAngle = parseInt($j("#input-numeric-rotate-angle", doc).val(), 10) * Math.PI / 180;\r
-                                               }\r
-                                               var onmousemove = function(e) {\r
-                                                       if (!mouseIsDown) return;\r
-\r
-                                                       var offset = $displayCanvas.offset();\r
-                                                       mx = (e.pageX - offset.left) - $displayCanvas.attr("width")*0.5;\r
-                                                       my = (e.pageY - offset.top) - $displayCanvas.attr("height")*0.5;\r
-                                                       deltaAngle = Math.atan2(my, mx) - startMouseAngle;\r
-                                                       angle = startAngle - deltaAngle;\r
-                                                       if (angle < -Math.PI) angle += 2*Math.PI;\r
-                                                       if (angle > Math.PI) angle -= 2*Math.PI;\r
-                                                       $j("#input-numeric-rotate-angle", doc).val(Math.round(angle * 180 / Math.PI));\r
-                                                       $j("#input-numeric-rotate-angle", doc).change();\r
-                                               }\r
-                                               var onmouseup = function() {\r
-                                                       mouseIsDown = false;\r
-                                               }\r
-\r
-                                               $j("#image-area", doc).bind("mousedown", onmousedown);\r
-                                               $j("#image-area", doc).bind("mousemove", onmousemove);\r
-                                               $j("#image-area", doc).bind("mouseup", onmouseup);\r
-                                               $canvas.data("onmousedown", onmousedown);\r
-                                               $canvas.data("onmousemove", onmousemove);\r
-                                               $canvas.data("onmouseup", onmouseup);\r
-                                               $displayCanvas.data("rotateCanvas", $canvas);\r
-                                       },\r
-                                       ondeactivate : function() {\r
-                                               var doc = PE.getDocument();\r
-                                               var $displayCanvas = PE.getDisplayCanvas();\r
-                                               $overlay = PE.getOverlay();\r
-                                               $j("#image-area", doc).css("cursor", "default");\r
-\r
-                                               var $canvas = $displayCanvas.data("rotateCanvas");\r
-\r
-                                               $j("#image-area", doc).unbind("mousedown", $canvas.data("onmousedown"));\r
-                                               $j("#image-area", doc).unbind("mousemove", $canvas.data("onmousemove"));\r
-                                               $j("#image-area", doc).unbind("mouseup", $canvas.data("onmouseup"));\r
-                                               $displayCanvas.removeData("rotateCanvas");\r
-                                               $canvas.remove();\r
-                                       },\r
-                                       onafteraction : function(action, isPreview) {\r
-                                               if (!isPreview) { // rebuild the rotate widget\r
-                                                       action.ondeactivate();\r
-                                                       action.onactivate();\r
-                                               }\r
-                                       },\r
-                                       onoverlayupdate : function() {\r
-                                               var $canvas = PE.getDisplayCanvas().data("rotateCanvas");\r
-                                               if ($canvas) {\r
-                                                       $canvas.css("marginTop", ((PE.getDisplayCanvas().get(0).height - $canvas.get(0).height) * 0.5) + "px");\r
-                                               }\r
-                                       }\r
-                               },\r
-                               {\r
-                                       title : "Flip",\r
-                                       id : "flip",\r
-                                       isAction : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       label : "Axis",\r
-                                                       option : "axis",\r
-                                                       type : "string", \r
-                                                       values : [\r
-                                                               {name:"Horizontal", value:"horizontal"},\r
-                                                               {name:"Vertical", value:"vertical"}\r
-                                                       ],\r
-                                                       defaultValue : "vertical",\r
-                                                       ui : "select"\r
-                                               }\r
-                                       ]\r
-                               }\r
-                       ]\r
-               },\r
-               {\r
-                       title : "Develop",\r
-                       id : "develop",\r
-                       actions : [\r
-                               {\r
-                                       title : "Brightness & Contrast",\r
-                                       id : "brightness",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Use the sliders below to adjust the brightness and/or contrast of the image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Brightness",\r
-                                                       option : "brightness",\r
-                                                       type : "number", \r
-                                                       range : [-100,100], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               },\r
-                                               {\r
-                                                       label : "Contrast",\r
-                                                       option : "contrast",\r
-                                                       type : "number", \r
-                                                       range : [-1,1], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Legacy mode",\r
-                                                       option : "legacy",\r
-                                                       type : "boolean", \r
-                                                       defaultValue : false,\r
-                                                       ui : "checkbox"\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Hue/Saturation/Lightness",\r
-                                       id : "hsl",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Use the sliders below to adjust the hue, saturation and/or lightness of the image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Hue",\r
-                                                       option : "hue",\r
-                                                       type : "number", \r
-                                                       range : [-180,180], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               },\r
-                                               {\r
-                                                       label : "Saturation",\r
-                                                       option : "saturation",\r
-                                                       type : "number", \r
-                                                       range : [-100,100], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               },\r
-                                               {\r
-                                                       label : "Lightness",\r
-                                                       option : "lightness",\r
-                                                       type : "number", \r
-                                                       range : [-100,100], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Adjust colors",\r
-                                       id : "coloradjust",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Use the sliders below to shift the R, G and B channels of the image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Red",\r
-                                                       option : "red",\r
-                                                       type : "number", \r
-                                                       range : [-1,1], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Green",\r
-                                                       option : "green",\r
-                                                       type : "number", \r
-                                                       range : [-1,1], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Blue",\r
-                                                       option : "blue",\r
-                                                       type : "number", \r
-                                                       range : [-1,1], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Desaturate",\r
-                                       id : "desaturate",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "This will desaturate the image. Select \"Use average\" to use the average value of the R, G and B channels rather than the default mix of 30% red, 59% green and 11% blue."\r
-                                               },\r
-                                               {\r
-                                                       label : "Use average",\r
-                                                       option : "average",\r
-                                                       type : "boolean", \r
-                                                       defaultValue : false,\r
-                                                       ui : "checkbox"\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Sepia toning",\r
-                                       id : "sepia",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Applies a sepia toning effect to the image."\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Invert",\r
-                                       id : "invert",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "This will invert the colors of the image."\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Lighten",\r
-                                       id : "lighten",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Use the slider below to lighten or darken the image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Amount",\r
-                                                       option : "amount",\r
-                                                       type : "number", \r
-                                                       range : [-1,1], \r
-                                                       defaultValue : 0,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Unsharp mask",\r
-                                       id : "unsharpmask",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Use the sliders below to adjust the unsharp mask parameters."\r
-                                               },\r
-                                               {\r
-                                                       label : "Amount",\r
-                                                       option : "amount",\r
-                                                       type : "number", \r
-                                                       range : [0,500], \r
-                                                       defaultValue : 200,\r
-                                                       ui : "slider",\r
-                                                       step : 2\r
-                                               },\r
-                                               {\r
-                                                       label : "Radius",\r
-                                                       option : "radius",\r
-                                                       type : "number", \r
-                                                       range : [0,5], \r
-                                                       defaultValue : 2,\r
-                                                       ui : "slider",\r
-                                                       step : 0.1\r
-                                               },\r
-                                               {\r
-                                                       label : "Threshold",\r
-                                                       option : "amount",\r
-                                                       type : "number", \r
-                                                       range : [0,255], \r
-                                                       defaultValue : 25,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               }\r
-                                       ]\r
-                               }\r
-\r
-                       ]\r
-               },\r
-               {\r
-                       title : "Effects",\r
-                       id : "effects",\r
-                       actions : [\r
-                               {\r
-                                       title : "Blur",\r
-                                       id : "blurfast",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Use the slider to set the blur amount."\r
-                                               },\r
-                                               {\r
-                                                       label : "Amount",\r
-                                                       option : "amount",\r
-                                                       type : "number", \r
-                                                       range : [0,1], \r
-                                                       defaultValue : 0.5,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               }\r
-                                       ]\r
-\r
-                               },\r
-                               {\r
-                                       title : "Edge detection",\r
-                                       id : "edges",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Performs edge detection on the image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Greyscale",\r
-                                                       option : "mono",\r
-                                                       type : "boolean", \r
-                                                       defaultValue : false,\r
-                                                       ui : "checkbox"\r
-                                               },\r
-                                               {\r
-                                                       label : "Invert",\r
-                                                       option : "invert",\r
-                                                       type : "boolean", \r
-                                                       defaultValue : false,\r
-                                                       ui : "checkbox"\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Emboss",\r
-                                       id : "emboss",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Adds an emboss-like effect to the image. Use the controls below to control the appearance of the effect. Choose \"Blend\" to blend the effect with the original image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Strength",\r
-                                                       option : "strength",\r
-                                                       type : "number", \r
-                                                       range : [0,10], \r
-                                                       defaultValue : 1,\r
-                                                       ui : "slider",\r
-                                                       step : 0.1\r
-                                               },\r
-                                               {\r
-                                                       label : "Grey level",\r
-                                                       option : "greyLevel",\r
-                                                       type : "number", \r
-                                                       range : [0,255], \r
-                                                       defaultValue : 180,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               },\r
-                                               {\r
-                                                       label : "Direction",\r
-                                                       option : "direction",\r
-                                                       type : "string", \r
-                                                       values : [\r
-                                                               {name:"Top left", value:"topleft"},\r
-                                                               {name:"Top", value:"top"},\r
-                                                               {name:"Top right", value:"topright"},\r
-                                                               {name:"Right", value:"right"},\r
-                                                               {name:"Bottom right", value:"bottomright"},\r
-                                                               {name:"Bottom", value:"bottom"},\r
-                                                               {name:"Bottom left", value:"bottomleft"},\r
-                                                               {name:"Left", value:"left"}\r
-                                                       ],\r
-                                                       defaultValue : "topleft",\r
-                                                       ui : "select"\r
-                                               },\r
-                                               {\r
-                                                       label : "Blend",\r
-                                                       option : "blend",\r
-                                                       type : "boolean", \r
-                                                       defaultValue : false,\r
-                                                       ui : "checkbox"\r
-                                               }\r
-                                       ]\r
-\r
-                               },\r
-                               {\r
-                                       title : "Glow",\r
-                                       id : "glow",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Creates a glowing effect on the image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Amount",\r
-                                                       option : "amount",\r
-                                                       type : "number", \r
-                                                       range : [0,1], \r
-                                                       defaultValue : 0.5,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Radius",\r
-                                                       option : "radius",\r
-                                                       type : "number", \r
-                                                       range : [0,1], \r
-                                                       defaultValue : 0.5,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Add noise",\r
-                                       id : "noise",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Add random noise to the image."\r
-                                               },\r
-                                               {\r
-                                                       label : "Amount",\r
-                                                       option : "amount",\r
-                                                       type : "number", \r
-                                                       range : [0,1], \r
-                                                       defaultValue : 0.5,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Strength",\r
-                                                       option : "strength",\r
-                                                       type : "number", \r
-                                                       range : [0,1], \r
-                                                       defaultValue : 0.5,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Greyscale",\r
-                                                       option : "mono",\r
-                                                       type : "boolean", \r
-                                                       defaultValue : false,\r
-                                                       ui : "checkbox"\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Remove noise",\r
-                                       id : "removenoise",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Attempts to remove noise from the image. Works best for getting rid of single pixels that stand out."\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Pointillize",\r
-                                       id : "pointillize",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Paints the picture with circular points."\r
-                                               },\r
-                                               {\r
-                                                       label : "Point radius",\r
-                                                       option : "radius",\r
-                                                       type : "number", \r
-                                                       range : [1,50], \r
-                                                       defaultValue : 5,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               },\r
-                                               {\r
-                                                       label : "Density",\r
-                                                       option : "density",\r
-                                                       type : "number", \r
-                                                       range : [0,5], \r
-                                                       defaultValue : 1,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Noise",\r
-                                                       option : "noise",\r
-                                                       type : "number", \r
-                                                       range : [0,2], \r
-                                                       defaultValue : 1,\r
-                                                       ui : "slider",\r
-                                                       step : 0.01\r
-                                               },\r
-                                               {\r
-                                                       label : "Transparent",\r
-                                                       option : "transparent",\r
-                                                       type : "boolean", \r
-                                                       defaultValue : false,\r
-                                                       ui : "checkbox"\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Posterize",\r
-                                       id : "posterize",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Reduces the number of colours to a specified number of levels."\r
-                                               },\r
-                                               {\r
-                                                       label : "Levels",\r
-                                                       option : "levels",\r
-                                                       type : "number", \r
-                                                       range : [1,32], \r
-                                                       defaultValue : 5,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Solarize",\r
-                                       id : "solarize",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Applies a solarize effect to the image."\r
-                                               }\r
-                                       ]\r
-                               },\r
-                               {\r
-                                       title : "Mosaic",\r
-                                       id : "mosaic",\r
-                                       isAction : true,\r
-                                       preview : true,\r
-                                       controls : [\r
-                                               {\r
-                                                       type : "output",\r
-                                                       content : "Creates a pixelated look."\r
-                                               },\r
-                                               {\r
-                                                       label : "Block size",\r
-                                                       option : "blockSize",\r
-                                                       type : "number", \r
-                                                       range : [1,100], \r
-                                                       defaultValue : 5,\r
-                                                       ui : "slider",\r
-                                                       step : 1\r
-                                               }\r
-                                       ]\r
-                               }\r
-\r
-\r
-                       ]\r
-               },\r
-               {\r
-                       title : "Done",\r
-                       id : "done",\r
-                       actions : [\r
-                               {\r
-                                       title : "Save to page",\r
-                                       id : "savepage",\r
-                                       content : function($ctr) {\r
-                                               var doc = PE.getDocument();\r
-                                               $j("<div></div>", doc)\r
-                                                       .addClass("action-output-text")\r
-                                                       .html("This will save the image to the page.")\r
-                                                       .appendTo($ctr);\r
-\r
-                                               var $buttonCtr = $j("<div></div>", doc).appendTo($ctr);\r
-                                               var $saveButton = $j("<button></button>", doc)\r
-                                                       .html("Save image")\r
-                                                       .appendTo($buttonCtr)\r
-                                                       .click(function() {\r
-                                                               PE.saveToPage();\r
-                                                       });\r
-\r
-                                       }\r
-                               },\r
-                               {\r
-                                       title : "Save to file",\r
-                                       id : "savefile",\r
-                                       content : function(ctr) {\r
-                                               var doc = PE.getDocument();\r
-                                               $j("<div></div>", doc)\r
-                                                       .addClass("action-output-text")\r
-                                                       .html("This will save the image to your local computer.")\r
-                                                       .appendTo(ctr);\r
-\r
-                                               var formats = PE.validSaveFormats();\r
-\r
-                                               var selectHtml = "<select>";\r
-                                               for (var i=0;i<formats.length;i++) {\r
-                                                       selectHtml += "<option value='" + formats[i].mime + "'>" + formats[i].name + "</option>";\r
-                                               }\r
-                                               selectHtml += "</select>";\r
-\r
-                                               var selectCtr = $j("<div></div>", doc)\r
-                                                       .addClass("ui-select-container");\r
-\r
-\r
-                                               var label = $j("<div></div>", doc)\r
-                                                       .addClass("ui-select-label")\r
-                                                       .html("Format:")\r
-                                                       .appendTo(selectCtr);\r
-\r
-                                               var formatSelect = $j(selectHtml, doc).appendTo(selectCtr);\r
-\r
-\r
-                                               selectCtr.appendTo(ctr);\r
-\r
-                                               var buttonCtr = $j("<div></div>", doc).appendTo(ctr);\r
-                                               var saveButton = $j("<button></button>", doc)\r
-                                                       .html("Save file")\r
-                                                       .appendTo(buttonCtr)\r
-\r
-                                               saveButton.click(function() {\r
-                                                       var selectElement = formatSelect.get(0);\r
-                                                       var formatMime = selectElement.options[selectElement.selectedIndex].value;\r
-                                                       var dataString = PE.getDataURI(formatMime);\r
-\r
-                                                       var dialog = $j("<div></div>", doc)\r
-                                                               .attr("id", "save-dialog")\r
-                                                               .attr("title", "Download file")\r
-                                                               .html(\r
-                                                                       "Right click the link below and select \"Save as...\" to save your file.<br/>"\r
-                                                                       + "<br/>"\r
-                                                                       + "<a href=\"" + dataString + "\">Image Link</a>"\r
-                                                               )\r
-                                                               .dialog();\r
-\r
-                                                       // the dialog is added outside the Pixastic container, so get it back in.\r
-                                                       var dialogParent = $j(dialog.get(0).parentNode);\r
-                                                       $j("#pixastic-editor", doc).append(dialogParent);\r
-                                               });\r
-                                       }\r
-                               },\r
-                               /*\r
-                               {\r
-                                       title : "Upload to Flickr",\r
-                                       id : "flickrupload",\r
-                                       content : function($ctr) {\r
-                                               var doc = PE.getDocument();\r
-\r
-                                               function flickrAuthed() {\r
-                                                       var $text = $j("<div />", doc)\r
-                                                               .addClass("action-output-text")\r
-                                                               .html("Authorized as: " + PE.Flickr.getAuthName());\r
-\r
-                                                       var $buttonCtr = $j("<div></div>", doc);\r
-                                                       var $uploadButton = $j("<button></button>", doc)\r
-                                                               .html("Upload image")\r
-                                                               .appendTo($buttonCtr)\r
-\r
-                                                       $uploadButton.click(function() {\r
-                                                               PE.Flickr.uploadImage(PE.getDataURI());\r
-                                                       });\r
-\r
-                                                       $ctr.append($text, $buttonCtr);\r
-                                               }\r
-\r
-                                               var $authCtr = $j("<div />", doc).appendTo($ctr);\r
-\r
-                                               $j("<div />", doc)\r
-                                                       .addClass("action-output-text")\r
-                                                       .html("If you have a Flickr account you can now upload your image to Flickr. You will need to give access to your account first. Click the button below to open an authorization window.")\r
-                                                       .appendTo($authCtr);\r
-\r
-                                               var $buttonCtr = $j("<div></div>", doc).appendTo($authCtr);\r
-                                               var $authButton = $j("<button></button>", doc)\r
-                                                       .html("Authenticate")\r
-                                                       .appendTo($buttonCtr)\r
-\r
-                                               var checkButtonAdded = false;\r
-                                               $authButton.click(function() {\r
-                                                       PE.Flickr.auth();\r
-                                                       if (!checkButtonAdded) {\r
-                                                               checkButtonAdded = true;\r
-\r
-                                                               var $text = $j("<div />", doc)\r
-                                                                       .addClass("action-output-text")\r
-                                                                       .html("Now click the button below when you have authorized access to your Flickr account.");\r
-       \r
-                                                               var $buttonCtr = $j("<div></div>", doc);\r
-       \r
-                                                               $authCtr.append($text, $buttonCtr);\r
-       \r
-                                                               var $checkButton = $j("<button></button>", doc)\r
-                                                                       .html("I have authenticated!")\r
-                                                                       .appendTo($buttonCtr);\r
-       \r
-                                                               $checkButton.click(function() {\r
-                                                                       PE.Flickr.checkAuth(function(res) {\r
-                                                                               if (res.stat == "ok") {\r
-                                                                                       $authCtr.remove();\r
-                                                                                       flickrAuthed();\r
-                                                                               }\r
-                                                                       });\r
-                                                               });\r
-                                                       }\r
-\r
-                                               });\r
-                                       }\r
-                               },\r
-                               */\r
-                               {\r
-                                       title : "Quit",\r
-                                       id : "quit", \r
-                                       content : function(ctr) {\r
-                                               var doc = PE.getDocument();\r
-\r
-                                               $j("<div>Are you sure you want to quit?</div>", doc)\r
-                                                       .addClass("action-output-text")\r
-                                                       .appendTo(ctr);\r
-                                               var $buttonCtr = $j("<div></div>", doc).appendTo(ctr);\r
-\r
-                                               var $quitButton = PE.UI.makeButton("Yes, quit now!")\r
-                                                       .appendTo($buttonCtr)\r
-\r
-                                               $quitButton.click(function() {\r
-                                                       PE.unload();\r
-                                               });\r
-\r
-                                               var $saveButton = PE.UI.makeButton("Save to page and quit")\r
-                                                       .appendTo($buttonCtr)\r
-                                                       .click(function() {\r
-                                                               PE.saveToPage();\r
-                                                               PE.unload();\r
-                                                       });\r
-                                       }\r
-                               }\r
-                       ]\r
-               }\r
-       ]\r
-};\r
-\r
-\r
+(function($) {
+
+var PE = PixasticEditor;
+
+PE.UI.data = {
+       tabs : [
+               {
+                       title : "Reshape",
+                       id : "reshape",
+                       actions : [
+                               {
+                                       title : "Resize",
+                                       id : "resize",
+                                       isAction : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Enter new dimensions below."
+                                               },
+                                               {
+                                                       label : "Width",
+                                                       labelRight : "px",
+                                                       option : "width",
+                                                       type : "number", 
+                                                       range : [1,10000], 
+                                                       step : 1,
+                                                       defaultValue : function() { return PE.getImageWidth(); },
+                                                       ui : "text"
+                                               },
+                                               {
+                                                       label : "Height",
+                                                       labelRight : "px",
+                                                       option : "height",
+                                                       type : "number", 
+                                                       range : [1,10000], 
+                                                       step : 1,
+                                                       defaultValue : function() { return PE.getImageHeight(); },
+                                                       ui : "text"
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Crop",
+                                       id : "crop",
+                                       isAction : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Enter new crop values below or use mouse to select crop area."
+                                               },
+                                               {
+                                                       label : "X",
+                                                       labelRight : "px",
+                                                       option : "left",
+                                                       type : "number", 
+                                                       range : [0,10000], 
+                                                       step : 1,
+                                                       defaultValue : 0,
+                                                       ui : "text"
+                                               },
+                                               {
+                                                       label : "Y",
+                                                       labelRight : "px",
+                                                       option : "top",
+                                                       type : "number", 
+                                                       range : [0,10000], 
+                                                       step : 1,
+                                                       defaultValue : 0,
+                                                       ui : "text"
+                                               },
+                                               {
+                                                       label : "Width",
+                                                       labelRight : "px",
+                                                       option : "width",
+                                                       type : "number", 
+                                                       range : [1,10000], 
+                                                       step : 1,
+                                                       defaultValue : function() { return PE.getImageWidth(); },
+                                                       ui : "text"
+                                               },
+                                               {
+                                                       label : "Height",
+                                                       labelRight : "px",
+                                                       option : "height",
+                                                       type : "number", 
+                                                       range : [1,10000], 
+                                                       step : 1,
+                                                       defaultValue : function() { return PE.getImageHeight(); },
+                                                       ui : "text"
+                                               }
+                                       ],
+                                       onactivate : function() {
+                                               var $canvas = PE.getDisplayCanvas();
+                                               var onchange = function(c) {
+                                                       var doc = PE.getDocument();
+                                                       $j("#input-numeric-crop-left", doc).val(c.x).change();
+                                                       $j("#input-numeric-crop-top", doc).val(c.y).change();
+                                                       $j("#input-numeric-crop-width", doc).val(c.w).change();
+                                                       $j("#input-numeric-crop-height", doc).val(c.h).change();
+                                                       $j("#input-hidden-crop-left", doc).val(c.x).change();
+                                                       $j("#input-hidden-crop-top", doc).val(c.y).change();
+                                                       $j("#input-hidden-crop-width", doc).val(c.w).change();
+                                                       $j("#input-hidden-crop-height", doc).val(c.h).change();
+                                               }
+                                               $canvas.data("Jcrop-onchange", onchange);
+                                               $canvas.Jcrop({onChange:onchange}, PE.getDocument());
+                                       },
+                                       ondeactivate : function() {
+                                               var $canvas = PE.getDisplayCanvas();
+                                               if ($canvas.data("Jcrop") && $canvas.data("Jcrop").destroy)
+                                                       $canvas.data("Jcrop").destroy();
+                                       },
+                                       onafteraction : function(action, isPreview) {
+                                               action.ondeactivate();
+                                               action.onactivate();
+                                               /*
+                                               var $canvas = PE.getDisplayCanvas();
+                                               if ($canvas.data("Jcrop") && $canvas.data("Jcrop").destroy)
+                                                       $canvas.data("Jcrop").destroy();
+                                               var onchange = $canvas.data("Jcrop-onchange");
+                                               $canvas.Jcrop({onChange:onchange});
+                                               */
+                                       }
+                               },
+                               {
+                                       title : "Rotate",
+                                       id : "rotate",
+                                       isAction : true,
+                                       preview : true,
+                                       forcePreview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Enter the angle (-180&deg; to 180&deg;) you want to rotate the picture. Use negative values for clockwise rotation, positive for counterclockwise."
+                                               },
+                                               {
+                                                       label : "Angle",
+                                                       labelRight : "&deg;",
+                                                       option : "angle",
+                                                       type : "number", 
+                                                       range : [-180,180], 
+                                                       step : 1,
+                                                       defaultValue : 0,
+                                                       ui : "text"
+                                               }
+                                       ],
+                                       onactivate : function() {
+                                               var doc = PE.getDocument();
+                                               var $displayCanvas = PE.getDisplayCanvas();
+                                               var dim = Math.min($displayCanvas.attr("height"), 200);
+                                               var $canvas = $j("<canvas></canvas>", doc);
+                                               PE.getOverlay().append($canvas);
+
+                                               $canvas.attr("width", dim);
+                                               $canvas.attr("height", dim);
+                                               $canvas.width(dim);
+                                               $canvas.height(dim);
+
+                                               $canvas.css("marginTop", (($displayCanvas.attr("height") - dim) * 0.5) + "px");
+
+                                               var lineWidth = 20;
+                                               var radius = dim/2 - lineWidth;
+                                               if (radius < 1) radius = 1;
+
+                                               var ctx = $canvas.get(0).getContext("2d");
+                                               ctx.beginPath()
+                                               ctx.arc(dim/2, dim/2, radius, 0, Math.PI*2, true);
+                                               ctx.closePath();
+                                               ctx.fillStyle = "rgba(200,200,200,0.2)";
+                                               ctx.fill();
+                                               ctx.strokeStyle = "rgba(200,200,200,0.5)";
+                                               ctx.lineWidth = 20;
+                                               ctx.stroke();
+
+                                               $j("#image-area", doc).css("cursor", "move");
+
+                                               $overlay = PE.getOverlay();
+
+                                               $canvas.get(0).ondragstart = function() {return false;}
+                                               $canvas.get(0).onselectstart = function() {return false;}
+
+                                               var mx = 0, my = 0;
+                                               var startMouseAngle = 0;
+                                               var startAngle = 0;
+                                               var deltaAngle = 0;
+                                               var angle = 0;
+
+                                               var mouseIsDown = false;
+                                               var onmousedown = function(e) {
+                                                       mouseIsDown = true;
+                                                       var offset = $displayCanvas.offset();
+                                                       mx = (e.pageX - offset.left) - $displayCanvas.attr("width")*0.5;
+                                                       my = (e.pageY - offset.top) - $displayCanvas.attr("height")*0.5;
+                                                       startMouseAngle = Math.atan2(my, mx);
+                                                       startAngle = parseInt($j("#input-numeric-rotate-angle", doc).val(), 10) * Math.PI / 180;
+                                               }
+                                               var onmousemove = function(e) {
+                                                       if (!mouseIsDown) return;
+
+                                                       var offset = $displayCanvas.offset();
+                                                       mx = (e.pageX - offset.left) - $displayCanvas.attr("width")*0.5;
+                                                       my = (e.pageY - offset.top) - $displayCanvas.attr("height")*0.5;
+                                                       deltaAngle = Math.atan2(my, mx) - startMouseAngle;
+                                                       angle = startAngle - deltaAngle;
+                                                       if (angle < -Math.PI) angle += 2*Math.PI;
+                                                       if (angle > Math.PI) angle -= 2*Math.PI;
+                                                       $j("#input-numeric-rotate-angle", doc).val(Math.round(angle * 180 / Math.PI));
+                                                       $j("#input-numeric-rotate-angle", doc).change();
+                                               }
+                                               var onmouseup = function() {
+                                                       mouseIsDown = false;
+                                               }
+
+                                               $j("#image-area", doc).bind("mousedown", onmousedown);
+                                               $j("#image-area", doc).bind("mousemove", onmousemove);
+                                               $j("#image-area", doc).bind("mouseup", onmouseup);
+                                               $canvas.data("onmousedown", onmousedown);
+                                               $canvas.data("onmousemove", onmousemove);
+                                               $canvas.data("onmouseup", onmouseup);
+                                               $displayCanvas.data("rotateCanvas", $canvas);
+                                       },
+                                       ondeactivate : function() {
+                                               var doc = PE.getDocument();
+                                               var $displayCanvas = PE.getDisplayCanvas();
+                                               $overlay = PE.getOverlay();
+                                               $j("#image-area", doc).css("cursor", "default");
+
+                                               var $canvas = $displayCanvas.data("rotateCanvas");
+
+                                               $j("#image-area", doc).unbind("mousedown", $canvas.data("onmousedown"));
+                                               $j("#image-area", doc).unbind("mousemove", $canvas.data("onmousemove"));
+                                               $j("#image-area", doc).unbind("mouseup", $canvas.data("onmouseup"));
+                                               $displayCanvas.removeData("rotateCanvas");
+                                               $canvas.remove();
+                                       },
+                                       onafteraction : function(action, isPreview) {
+                                               if (!isPreview) { // rebuild the rotate widget
+                                                       action.ondeactivate();
+                                                       action.onactivate();
+                                               }
+                                       },
+                                       onoverlayupdate : function() {
+                                               var $canvas = PE.getDisplayCanvas().data("rotateCanvas");
+                                               if ($canvas) {
+                                                       $canvas.css("marginTop", ((PE.getDisplayCanvas().get(0).height - $canvas.get(0).height) * 0.5) + "px");
+                                               }
+                                       }
+                               },
+                               {
+                                       title : "Flip",
+                                       id : "flip",
+                                       isAction : true,
+                                       controls : [
+                                               {
+                                                       label : "Axis",
+                                                       option : "axis",
+                                                       type : "string", 
+                                                       values : [
+                                                               {name:"Horizontal", value:"horizontal"},
+                                                               {name:"Vertical", value:"vertical"}
+                                                       ],
+                                                       defaultValue : "vertical",
+                                                       ui : "select"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
+               {
+                       title : "Develop",
+                       id : "develop",
+                       actions : [
+                               {
+                                       title : "Brightness & Contrast",
+                                       id : "brightness",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Use the sliders below to adjust the brightness and/or contrast of the image."
+                                               },
+                                               {
+                                                       label : "Brightness",
+                                                       option : "brightness",
+                                                       type : "number", 
+                                                       range : [-100,100], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 1
+                                               },
+                                               {
+                                                       label : "Contrast",
+                                                       option : "contrast",
+                                                       type : "number", 
+                                                       range : [-1,1], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Legacy mode",
+                                                       option : "legacy",
+                                                       type : "boolean", 
+                                                       defaultValue : false,
+                                                       ui : "checkbox"
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Hue/Saturation/Lightness",
+                                       id : "hsl",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Use the sliders below to adjust the hue, saturation and/or lightness of the image."
+                                               },
+                                               {
+                                                       label : "Hue",
+                                                       option : "hue",
+                                                       type : "number", 
+                                                       range : [-180,180], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 1
+                                               },
+                                               {
+                                                       label : "Saturation",
+                                                       option : "saturation",
+                                                       type : "number", 
+                                                       range : [-100,100], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 1
+                                               },
+                                               {
+                                                       label : "Lightness",
+                                                       option : "lightness",
+                                                       type : "number", 
+                                                       range : [-100,100], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 1
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Adjust colors",
+                                       id : "coloradjust",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Use the sliders below to shift the R, G and B channels of the image."
+                                               },
+                                               {
+                                                       label : "Red",
+                                                       option : "red",
+                                                       type : "number", 
+                                                       range : [-1,1], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Green",
+                                                       option : "green",
+                                                       type : "number", 
+                                                       range : [-1,1], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Blue",
+                                                       option : "blue",
+                                                       type : "number", 
+                                                       range : [-1,1], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Desaturate",
+                                       id : "desaturate",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "This will desaturate the image. Select \"Use average\" to use the average value of the R, G and B channels rather than the default mix of 30% red, 59% green and 11% blue."
+                                               },
+                                               {
+                                                       label : "Use average",
+                                                       option : "average",
+                                                       type : "boolean", 
+                                                       defaultValue : false,
+                                                       ui : "checkbox"
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Sepia toning",
+                                       id : "sepia",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Applies a sepia toning effect to the image."
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Invert",
+                                       id : "invert",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "This will invert the colors of the image."
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Lighten",
+                                       id : "lighten",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Use the slider below to lighten or darken the image."
+                                               },
+                                               {
+                                                       label : "Amount",
+                                                       option : "amount",
+                                                       type : "number", 
+                                                       range : [-1,1], 
+                                                       defaultValue : 0,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Unsharp mask",
+                                       id : "unsharpmask",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Use the sliders below to adjust the unsharp mask parameters."
+                                               },
+                                               {
+                                                       label : "Amount",
+                                                       option : "amount",
+                                                       type : "number", 
+                                                       range : [0,500], 
+                                                       defaultValue : 200,
+                                                       ui : "slider",
+                                                       step : 2
+                                               },
+                                               {
+                                                       label : "Radius",
+                                                       option : "radius",
+                                                       type : "number", 
+                                                       range : [0,5], 
+                                                       defaultValue : 2,
+                                                       ui : "slider",
+                                                       step : 0.1
+                                               },
+                                               {
+                                                       label : "Threshold",
+                                                       option : "amount",
+                                                       type : "number", 
+                                                       range : [0,255], 
+                                                       defaultValue : 25,
+                                                       ui : "slider",
+                                                       step : 1
+                                               }
+                                       ]
+                               }
+
+                       ]
+               },
+               {
+                       title : "Effects",
+                       id : "effects",
+                       actions : [
+                               {
+                                       title : "Blur",
+                                       id : "blurfast",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Use the slider to set the blur amount."
+                                               },
+                                               {
+                                                       label : "Amount",
+                                                       option : "amount",
+                                                       type : "number", 
+                                                       range : [0,1], 
+                                                       defaultValue : 0.5,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               }
+                                       ]
+
+                               },
+                               {
+                                       title : "Edge detection",
+                                       id : "edges",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Performs edge detection on the image."
+                                               },
+                                               {
+                                                       label : "Greyscale",
+                                                       option : "mono",
+                                                       type : "boolean", 
+                                                       defaultValue : false,
+                                                       ui : "checkbox"
+                                               },
+                                               {
+                                                       label : "Invert",
+                                                       option : "invert",
+                                                       type : "boolean", 
+                                                       defaultValue : false,
+                                                       ui : "checkbox"
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Emboss",
+                                       id : "emboss",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Adds an emboss-like effect to the image. Use the controls below to control the appearance of the effect. Choose \"Blend\" to blend the effect with the original image."
+                                               },
+                                               {
+                                                       label : "Strength",
+                                                       option : "strength",
+                                                       type : "number", 
+                                                       range : [0,10], 
+                                                       defaultValue : 1,
+                                                       ui : "slider",
+                                                       step : 0.1
+                                               },
+                                               {
+                                                       label : "Grey level",
+                                                       option : "greyLevel",
+                                                       type : "number", 
+                                                       range : [0,255], 
+                                                       defaultValue : 180,
+                                                       ui : "slider",
+                                                       step : 1
+                                               },
+                                               {
+                                                       label : "Direction",
+                                                       option : "direction",
+                                                       type : "string", 
+                                                       values : [
+                                                               {name:"Top left", value:"topleft"},
+                                                               {name:"Top", value:"top"},
+                                                               {name:"Top right", value:"topright"},
+                                                               {name:"Right", value:"right"},
+                                                               {name:"Bottom right", value:"bottomright"},
+                                                               {name:"Bottom", value:"bottom"},
+                                                               {name:"Bottom left", value:"bottomleft"},
+                                                               {name:"Left", value:"left"}
+                                                       ],
+                                                       defaultValue : "topleft",
+                                                       ui : "select"
+                                               },
+                                               {
+                                                       label : "Blend",
+                                                       option : "blend",
+                                                       type : "boolean", 
+                                                       defaultValue : false,
+                                                       ui : "checkbox"
+                                               }
+                                       ]
+
+                               },
+                               {
+                                       title : "Glow",
+                                       id : "glow",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Creates a glowing effect on the image."
+                                               },
+                                               {
+                                                       label : "Amount",
+                                                       option : "amount",
+                                                       type : "number", 
+                                                       range : [0,1], 
+                                                       defaultValue : 0.5,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Radius",
+                                                       option : "radius",
+                                                       type : "number", 
+                                                       range : [0,1], 
+                                                       defaultValue : 0.5,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Add noise",
+                                       id : "noise",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Add random noise to the image."
+                                               },
+                                               {
+                                                       label : "Amount",
+                                                       option : "amount",
+                                                       type : "number", 
+                                                       range : [0,1], 
+                                                       defaultValue : 0.5,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Strength",
+                                                       option : "strength",
+                                                       type : "number", 
+                                                       range : [0,1], 
+                                                       defaultValue : 0.5,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Greyscale",
+                                                       option : "mono",
+                                                       type : "boolean", 
+                                                       defaultValue : false,
+                                                       ui : "checkbox"
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Remove noise",
+                                       id : "removenoise",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Attempts to remove noise from the image. Works best for getting rid of single pixels that stand out."
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Pointillize",
+                                       id : "pointillize",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Paints the picture with circular points."
+                                               },
+                                               {
+                                                       label : "Point radius",
+                                                       option : "radius",
+                                                       type : "number", 
+                                                       range : [1,50], 
+                                                       defaultValue : 5,
+                                                       ui : "slider",
+                                                       step : 1
+                                               },
+                                               {
+                                                       label : "Density",
+                                                       option : "density",
+                                                       type : "number", 
+                                                       range : [0,5], 
+                                                       defaultValue : 1,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Noise",
+                                                       option : "noise",
+                                                       type : "number", 
+                                                       range : [0,2], 
+                                                       defaultValue : 1,
+                                                       ui : "slider",
+                                                       step : 0.01
+                                               },
+                                               {
+                                                       label : "Transparent",
+                                                       option : "transparent",
+                                                       type : "boolean", 
+                                                       defaultValue : false,
+                                                       ui : "checkbox"
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Posterize",
+                                       id : "posterize",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Reduces the number of colours to a specified number of levels."
+                                               },
+                                               {
+                                                       label : "Levels",
+                                                       option : "levels",
+                                                       type : "number", 
+                                                       range : [1,32], 
+                                                       defaultValue : 5,
+                                                       ui : "slider",
+                                                       step : 1
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Solarize",
+                                       id : "solarize",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Applies a solarize effect to the image."
+                                               }
+                                       ]
+                               },
+                               {
+                                       title : "Mosaic",
+                                       id : "mosaic",
+                                       isAction : true,
+                                       preview : true,
+                                       controls : [
+                                               {
+                                                       type : "output",
+                                                       content : "Creates a pixelated look."
+                                               },
+                                               {
+                                                       label : "Block size",
+                                                       option : "blockSize",
+                                                       type : "number", 
+                                                       range : [1,100], 
+                                                       defaultValue : 5,
+                                                       ui : "slider",
+                                                       step : 1
+                                               }
+                                       ]
+                               }
+
+
+                       ]
+               },
+               {
+                       title : "Done",
+                       id : "done",
+                       actions : [
+                               {
+                                       title : "Save to page",
+                                       id : "savepage",
+                                       content : function($ctr) {
+                                               var doc = PE.getDocument();
+                                               $j("<div></div>", doc)
+                                                       .addClass("action-output-text")
+                                                       .html("This will save the image to the page.")
+                                                       .appendTo($ctr);
+
+                                               var $buttonCtr = $j("<div></div>", doc).appendTo($ctr);
+                                               var $saveButton = $j("<button></button>", doc)
+                                                       .html("Save image")
+                                                       .appendTo($buttonCtr)
+                                                       .click(function() {
+                                                               PE.saveToPage();
+                                                       });
+
+                                       }
+                               },
+                               {
+                                       title : "Save to file",
+                                       id : "savefile",
+                                       content : function(ctr) {
+                                               var doc = PE.getDocument();
+                                               $j("<div></div>", doc)
+                                                       .addClass("action-output-text")
+                                                       .html("This will save the image to your local computer.")
+                                                       .appendTo(ctr);
+
+                                               var formats = PE.validSaveFormats();
+
+                                               var selectHtml = "<select>";
+                                               for (var i=0;i<formats.length;i++) {
+                                                       selectHtml += "<option value='" + formats[i].mime + "'>" + formats[i].name + "</option>";
+                                               }
+                                               selectHtml += "</select>";
+
+                                               var selectCtr = $j("<div></div>", doc)
+                                                       .addClass("ui-select-container");
+
+
+                                               var label = $j("<div></div>", doc)
+                                                       .addClass("ui-select-label")
+                                                       .html("Format:")
+                                                       .appendTo(selectCtr);
+
+                                               var formatSelect = $j(selectHtml, doc).appendTo(selectCtr);
+
+
+                                               selectCtr.appendTo(ctr);
+
+                                               var buttonCtr = $j("<div></div>", doc).appendTo(ctr);
+                                               var saveButton = $j("<button></button>", doc)
+                                                       .html("Save file")
+                                                       .appendTo(buttonCtr)
+
+                                               saveButton.click(function() {
+                                                       var selectElement = formatSelect.get(0);
+                                                       var formatMime = selectElement.options[selectElement.selectedIndex].value;
+                                                       var dataString = PE.getDataURI(formatMime);
+
+                                                       var dialog = $j("<div></div>", doc)
+                                                               .attr("id", "save-dialog")
+                                                               .attr("title", "Download file")
+                                                               .html(
+                                                                       "Right click the link below and select \"Save as...\" to save your file.<br/>"
+                                                                       + "<br/>"
+                                                                       + "<a href=\"" + dataString + "\">Image Link</a>"
+                                                               )
+                                                               .dialog();
+
+                                                       // the dialog is added outside the Pixastic container, so get it back in.
+                                                       var dialogParent = $j(dialog.get(0).parentNode);
+                                                       $j("#pixastic-editor", doc).append(dialogParent);
+                                               });
+                                       }
+                               },
+                               /*
+                               {
+                                       title : "Upload to Flickr",
+                                       id : "flickrupload",
+                                       content : function($ctr) {
+                                               var doc = PE.getDocument();
+
+                                               function flickrAuthed() {
+                                                       var $text = $j("<div />", doc)
+                                                               .addClass("action-output-text")
+                                                               .html("Authorized as: " + PE.Flickr.getAuthName());
+
+                                                       var $buttonCtr = $j("<div></div>", doc);
+                                                       var $uploadButton = $j("<button></button>", doc)
+                                                               .html("Upload image")
+                                                               .appendTo($buttonCtr)
+
+                                                       $uploadButton.click(function() {
+                                                               PE.Flickr.uploadImage(PE.getDataURI());
+                                                       });
+
+                                                       $ctr.append($text, $buttonCtr);
+                                               }
+
+                                               var $authCtr = $j("<div />", doc).appendTo($ctr);
+
+                                               $j("<div />", doc)
+                                                       .addClass("action-output-text")
+                                                       .html("If you have a Flickr account you can now upload your image to Flickr. You will need to give access to your account first. Click the button below to open an authorization window.")
+                                                       .appendTo($authCtr);
+
+                                               var $buttonCtr = $j("<div></div>", doc).appendTo($authCtr);
+                                               var $authButton = $j("<button></button>", doc)
+                                                       .html("Authenticate")
+                                                       .appendTo($buttonCtr)
+
+                                               var checkButtonAdded = false;
+                                               $authButton.click(function() {
+                                                       PE.Flickr.auth();
+                                                       if (!checkButtonAdded) {
+                                                               checkButtonAdded = true;
+
+                                                               var $text = $j("<div />", doc)
+                                                                       .addClass("action-output-text")
+                                                                       .html("Now click the button below when you have authorized access to your Flickr account.");
+       
+                                                               var $buttonCtr = $j("<div></div>", doc);
+       
+                                                               $authCtr.append($text, $buttonCtr);
+       
+                                                               var $checkButton = $j("<button></button>", doc)
+                                                                       .html("I have authenticated!")
+                                                                       .appendTo($buttonCtr);
+       
+                                                               $checkButton.click(function() {
+                                                                       PE.Flickr.checkAuth(function(res) {
+                                                                               if (res.stat == "ok") {
+                                                                                       $authCtr.remove();
+                                                                                       flickrAuthed();
+                                                                               }
+                                                                       });
+                                                               });
+                                                       }
+
+                                               });
+                                       }
+                               },
+                               */
+                               {
+                                       title : "Quit",
+                                       id : "quit", 
+                                       content : function(ctr) {
+                                               var doc = PE.getDocument();
+
+                                               $j("<div>Are you sure you want to quit?</div>", doc)
+                                                       .addClass("action-output-text")
+                                                       .appendTo(ctr);
+                                               var $buttonCtr = $j("<div></div>", doc).appendTo(ctr);
+
+                                               var $quitButton = PE.UI.makeButton("Yes, quit now!")
+                                                       .appendTo($buttonCtr)
+
+                                               $quitButton.click(function() {
+                                                       PE.unload();
+                                               });
+
+                                               var $saveButton = PE.UI.makeButton("Save to page and quit")
+                                                       .appendTo($buttonCtr)
+                                                       .click(function() {
+                                                               PE.saveToPage();
+                                                               PE.unload();
+                                                       });
+                                       }
+                               }
+                       ]
+               }
+       ]
+};
+
+
 })(PixasticEditor.jQuery);
\ No newline at end of file