├── .debug ├── .gitignore ├── AEColorPicker.aex ├── AEColorPicker.plugin └── Contents │ ├── Info.plist │ ├── MacOS │ └── AEColorPicker │ ├── PkgInfo │ └── Resources │ └── AEColorPicker.rsrc ├── CSXS └── manifest.xml ├── LICENSE ├── README.md ├── css ├── lmroman-regular.woff ├── styles.css └── themeManager.css ├── icons ├── iconDarkNormal.png ├── iconDarkRollover.png ├── iconDisabled.png ├── iconNormal.png └── iconRollover.png ├── index.html ├── js ├── libs │ └── CSInterface.js ├── main.js ├── node_modules │ └── colorama_ffx │ │ ├── index.js │ │ └── package.json └── themeManager.js ├── jsx └── hostscript.jsx └── template.ffx /.debug: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coloramen.ffx -------------------------------------------------------------------------------- /AEColorPicker.aex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lachrymaLF/Coloramen/2fa9492294456c4971601573548bcbde1ee9c98a/AEColorPicker.aex -------------------------------------------------------------------------------- /AEColorPicker.plugin/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 16G2128 7 | CFBundleExecutable 8 | AEColorPicker 9 | CFBundleIdentifier 10 | com.PublicDomain.AEColorPicker 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | AEColorPicker 15 | CFBundlePackageType 16 | AEgx 17 | CFBundleSignature 18 | FXTC 19 | CFBundleSupportedPlatforms 20 | 21 | MacOSX 22 | 23 | DTCompiler 24 | com.apple.compilers.llvm.clang.1_0 25 | DTPlatformBuild 26 | 8A218a 27 | DTPlatformVersion 28 | GM 29 | DTSDKBuild 30 | 16A300 31 | DTSDKName 32 | macosx10.12 33 | DTXcode 34 | 0800 35 | DTXcodeBuild 36 | 8A218a 37 | LSRequiresCarbon 38 | 39 | NSAppleScriptEnabled 40 | No 41 | 42 | 43 | -------------------------------------------------------------------------------- /AEColorPicker.plugin/Contents/MacOS/AEColorPicker: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lachrymaLF/Coloramen/2fa9492294456c4971601573548bcbde1ee9c98a/AEColorPicker.plugin/Contents/MacOS/AEColorPicker -------------------------------------------------------------------------------- /AEColorPicker.plugin/Contents/PkgInfo: -------------------------------------------------------------------------------- 1 | AEgxFXTC -------------------------------------------------------------------------------- /AEColorPicker.plugin/Contents/Resources/AEColorPicker.rsrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lachrymaLF/Coloramen/2fa9492294456c4971601573548bcbde1ee9c98a/AEColorPicker.plugin/Contents/Resources/AEColorPicker.rsrc -------------------------------------------------------------------------------- /CSXS/manifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ./index.html 24 | ./jsx/hostscript.jsx 25 | 26 | --enable-nodejs 27 | 28 | 29 | 30 | true 31 | 32 | 33 | Panel 34 | Coloramen 35 | 36 | 37 | 300 38 | 300 39 | 40 | 48 | 49 | 50 | ./icons/iconNormal.png 51 | ./icons/iconRollover.png 52 | ./icons/iconDisabled.png 53 | ./icons/iconDarkNormal.png 54 | ./icons/iconDarkRollover.png 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 lachrymaL 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Coloramen 2 | 3 | Adobe After Effects CEP helper panel for the clunky Colorama effect 4 | 5 | ![GIF Demo](https://user-images.githubusercontent.com/13716477/116627160-980a7c80-a91a-11eb-9423-60a6f77192c9.gif) 6 | 7 | Achieved through direct manipulation of the animation preset binary 8 | 9 | ### Caveats 10 | - The data in [Source / Masks / Effects & Masks] options of Add Phase and Mask Layer will not be saved 11 | - Keyframes and expressions on the effect are not saved 12 | 13 | ### How it works 14 | Here is a diagram explaining the .ffx data stored for Colorama 15 | 16 | ![Explanation of Colorama data](https://i.imgur.com/U0D5Q5h.png) 17 | 18 | [Detailed discussion on Adobe Community](https://community.adobe.com/t5/after-effects/change-colorama-colors-via-scripting/m-p/10392133) 19 | 20 | Where the section of keys begin and end, and where the total number of keys is stored seem to differ from setup to setup. For the *template.ffx* provided in this repository, the keys starts on 2D1C and the byte containing the number of keys is stored in 2F1F. 21 | It also seems that the same data repeats once at 0CD0 and 0ED3 (keys and # of keys, respectively), but they do not seem to matter when the .ffx is applied. 22 | 23 | ### ID Labels of the effect (As of CC 2021 18.0.0, Colorama v1.1) 24 | 25 | ![Labels of Colorama](https://i.imgur.com/TLkFsAq.png) 26 | 27 | - Massive thanks to [Belonit/AEColorPicker](https://github.com/Belonit/AEColorPicker) 28 | -------------------------------------------------------------------------------- /css/lmroman-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lachrymaLF/Coloramen/2fa9492294456c4971601573548bcbde1ee9c98a/css/lmroman-regular.woff -------------------------------------------------------------------------------- /css/styles.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: Latin Modern; 3 | src: url('lmroman-regular.woff'); 4 | font-style: normal; 5 | } 6 | 7 | p, 8 | a, 9 | h1, 10 | h2, 11 | h3, 12 | h4, 13 | h5, 14 | h6, 15 | small, 16 | blockquote, 17 | li, 18 | button, 19 | input, 20 | td, 21 | th { 22 | color: white; 23 | font-family: Latin Modern, serif !important; 24 | } 25 | 26 | body { 27 | margin: 10px; 28 | background-color: black !important; 29 | } 30 | 31 | th, 32 | td { 33 | text-align: center; 34 | } 35 | 36 | table { 37 | table-layout: fixed; 38 | width: 100%; 39 | } 40 | 41 | #tab-table td { 42 | font-size: 15px; 43 | } 44 | 45 | #tab-table-labels th { 46 | font-size: 20px; 47 | } 48 | 49 | #tab-table-labels, 50 | #tab-table { 51 | border-top: 1px white solid; 52 | } 53 | 54 | #tab-table td { 55 | border-bottom: 1px white solid; 56 | } 57 | 58 | #tab-table-labels tr { 59 | background-color: rgba(255, 255, 255, .4) 60 | } 61 | 62 | #tab-table tr { 63 | transition: .1s; 64 | } 65 | 66 | #tab-table tr:hover { 67 | background-color: rgba(255, 255, 255, .2); 68 | } 69 | 70 | #tab-table tr:active, 71 | .tr-selected, 72 | #tab-table tr:active td { 73 | background-color: rgba(255, 255, 255, .8); 74 | color: black; 75 | } 76 | 77 | .tr-selected td { 78 | color: black; 79 | } 80 | 81 | button { 82 | height: 2.5em; 83 | background-color: transparent; 84 | border: 1px solid white; 85 | outline: none; 86 | transition: .1s; 87 | padding: 0; 88 | font-family: Symbola, sans-serif; 89 | font-size: 1.6em; 90 | } 91 | 92 | button:hover { 93 | background-color: white; 94 | color: black; 95 | } 96 | 97 | button:active { 98 | background-color: rgba(255, 255, 255, .2); 99 | } 100 | 101 | #content { 102 | margin-right: auto; 103 | margin-left: auto; 104 | vertical-align: middle; 105 | width: 100%; 106 | } 107 | 108 | #btn-apply { 109 | width: 100%; 110 | } 111 | 112 | #grad { 113 | height: 50px; 114 | margin-top: 10px; 115 | } 116 | 117 | #grad-container { 118 | background-image: repeating-linear-gradient(45deg, transparent, transparent 2%, rgba(128, 128, 128, 0.4) 2%, rgba(128, 128, 128, 0.4) 4%); 119 | outline: darkslategray 3px solid; 120 | } 121 | 122 | #gradtab-container { 123 | position: relative; 124 | height: 30px; 125 | margin: 5px 0 5px 0; 126 | } 127 | 128 | .gradtab { 129 | height: 100%; 130 | width: 10px; 131 | background-color: white; 132 | position: absolute; 133 | outline-style: solid; 134 | outline-width: 2px; 135 | outline-color: gray; 136 | } 137 | 138 | .gradtab:hover, 139 | #first-tab:hover, 140 | #last-tab:hover { 141 | outline-color: rgb(180, 180, 180); 142 | } 143 | 144 | .gradtab::after { 145 | content: ""; 146 | display: inline-block; 147 | position: absolute; 148 | border-width: 0px 5px 12px 5px; 149 | border-color: white transparent; 150 | border-style: solid; 151 | margin-top: -15px; 152 | } 153 | 154 | .gradtab::before { 155 | content: ""; 156 | display: inline-block; 157 | position: absolute; 158 | border-width: 0px 7px 14px 7px; 159 | border-color: black transparent; 160 | border-style: solid; 161 | margin-top: -17px; 162 | margin-left: -2px; 163 | } 164 | 165 | .selected { 166 | outline-color: salmon !important; 167 | z-index: 1; 168 | } 169 | 170 | #first-tab, 171 | #last-tab { 172 | outline-color: darkslategray; 173 | } 174 | 175 | #btn-table { 176 | border: 1px white solid; 177 | height: 100%; 178 | width: 95%; 179 | font-size: 2em; 180 | transition: .1s; 181 | } 182 | 183 | #btn-table:hover { 184 | background-color: rgba(255, 255, 255, .4); 185 | } 186 | 187 | .preview-block { 188 | width: 1.2em; 189 | height: 1.2em; 190 | right: 5px; 191 | position: absolute; 192 | display: inline-block; 193 | border: 2px gray solid; 194 | } 195 | 196 | #pos-input { 197 | height: 100%; 198 | width: 95%; 199 | background-color: transparent; 200 | color: white; 201 | text-align: center; 202 | font-size: 2em; 203 | border: 1px solid white; 204 | } 205 | 206 | #pos-input::selection { 207 | background-color: white; 208 | } 209 | 210 | #pos-input::-webkit-outer-spin-button, 211 | #pos-input::-webkit-inner-spin-button { 212 | -webkit-appearance: none; 213 | margin: 0; 214 | } 215 | 216 | .pushed { 217 | background-color: white; 218 | color: black; 219 | } 220 | 221 | .hidden { 222 | display: none; 223 | } -------------------------------------------------------------------------------- /css/themeManager.css: -------------------------------------------------------------------------------- 1 | /* 2 | Those classes will be edited at runtime with values specified 3 | by the settings of the CC application 4 | */ 5 | 6 | .hostFontColor {} 7 | 8 | .hostFontFamily {} 9 | 10 | .hostFontSize {} 11 | 12 | 13 | /*font family, color and size*/ 14 | 15 | .hostFont {} 16 | 17 | 18 | /*background color*/ 19 | 20 | .hostBgd {} 21 | 22 | 23 | /*lighter background color*/ 24 | 25 | .hostBgdLight {} 26 | 27 | 28 | /*darker background color*/ 29 | 30 | .hostBgdDark {} 31 | 32 | 33 | /*background color and font*/ 34 | 35 | .hostElt {} 36 | 37 | .hostButton { 38 | border: 1px solid; 39 | border-radius: 2px; 40 | height: 20px; 41 | vertical-align: bottom; 42 | font-family: inherit; 43 | color: inherit; 44 | font-size: inherit; 45 | } -------------------------------------------------------------------------------- /icons/iconDarkNormal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lachrymaLF/Coloramen/2fa9492294456c4971601573548bcbde1ee9c98a/icons/iconDarkNormal.png -------------------------------------------------------------------------------- /icons/iconDarkRollover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lachrymaLF/Coloramen/2fa9492294456c4971601573548bcbde1ee9c98a/icons/iconDarkRollover.png -------------------------------------------------------------------------------- /icons/iconDisabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lachrymaLF/Coloramen/2fa9492294456c4971601573548bcbde1ee9c98a/icons/iconDisabled.png -------------------------------------------------------------------------------- /icons/iconNormal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lachrymaLF/Coloramen/2fa9492294456c4971601573548bcbde1ee9c98a/icons/iconNormal.png -------------------------------------------------------------------------------- /icons/iconRollover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lachrymaLF/Coloramen/2fa9492294456c4971601573548bcbde1ee9c98a/icons/iconRollover.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Coloramen 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | 19 | 22 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
20 | 21 | 23 | 24 |
32 |
33 |
34 |
35 |
36 | 37 | 38 |
39 |
40 |
41 | 42 | 43 | 46 | 49 | 50 |
44 | 45 | 47 |
Table View
48 |
51 |
52 |
53 | 54 | 55 | 56 | 57 |
IndexPositionColor
58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
00%000000
1100%FFFFFF
70 |
71 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /js/libs/CSInterface.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************************** 2 | * 3 | * ADOBE SYSTEMS INCORPORATED 4 | * Copyright 2013 Adobe Systems Incorporated 5 | * All Rights Reserved. 6 | * 7 | * NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the 8 | * terms of the Adobe license agreement accompanying it. If you have received this file from a 9 | * source other than Adobe, then your use, modification, or distribution of it requires the prior 10 | * written permission of Adobe. 11 | * 12 | **************************************************************************************************/ 13 | 14 | /** CSInterface - v8.0.0 */ 15 | 16 | /** 17 | * Stores constants for the window types supported by the CSXS infrastructure. 18 | */ 19 | function CSXSWindowType() 20 | { 21 | } 22 | 23 | /** Constant for the CSXS window type Panel. */ 24 | CSXSWindowType._PANEL = "Panel"; 25 | 26 | /** Constant for the CSXS window type Modeless. */ 27 | CSXSWindowType._MODELESS = "Modeless"; 28 | 29 | /** Constant for the CSXS window type ModalDialog. */ 30 | CSXSWindowType._MODAL_DIALOG = "ModalDialog"; 31 | 32 | /** EvalScript error message */ 33 | EvalScript_ErrMessage = "EvalScript error."; 34 | 35 | /** 36 | * @class Version 37 | * Defines a version number with major, minor, micro, and special 38 | * components. The major, minor and micro values are numeric; the special 39 | * value can be any string. 40 | * 41 | * @param major The major version component, a positive integer up to nine digits long. 42 | * @param minor The minor version component, a positive integer up to nine digits long. 43 | * @param micro The micro version component, a positive integer up to nine digits long. 44 | * @param special The special version component, an arbitrary string. 45 | * 46 | * @return A new \c Version object. 47 | */ 48 | function Version(major, minor, micro, special) 49 | { 50 | this.major = major; 51 | this.minor = minor; 52 | this.micro = micro; 53 | this.special = special; 54 | } 55 | 56 | /** 57 | * The maximum value allowed for a numeric version component. 58 | * This reflects the maximum value allowed in PlugPlug and the manifest schema. 59 | */ 60 | Version.MAX_NUM = 999999999; 61 | 62 | /** 63 | * @class VersionBound 64 | * Defines a boundary for a version range, which associates a \c Version object 65 | * with a flag for whether it is an inclusive or exclusive boundary. 66 | * 67 | * @param version The \c #Version object. 68 | * @param inclusive True if this boundary is inclusive, false if it is exclusive. 69 | * 70 | * @return A new \c VersionBound object. 71 | */ 72 | function VersionBound(version, inclusive) 73 | { 74 | this.version = version; 75 | this.inclusive = inclusive; 76 | } 77 | 78 | /** 79 | * @class VersionRange 80 | * Defines a range of versions using a lower boundary and optional upper boundary. 81 | * 82 | * @param lowerBound The \c #VersionBound object. 83 | * @param upperBound The \c #VersionBound object, or null for a range with no upper boundary. 84 | * 85 | * @return A new \c VersionRange object. 86 | */ 87 | function VersionRange(lowerBound, upperBound) 88 | { 89 | this.lowerBound = lowerBound; 90 | this.upperBound = upperBound; 91 | } 92 | 93 | /** 94 | * @class Runtime 95 | * Represents a runtime related to the CEP infrastructure. 96 | * Extensions can declare dependencies on particular 97 | * CEP runtime versions in the extension manifest. 98 | * 99 | * @param name The runtime name. 100 | * @param version A \c #VersionRange object that defines a range of valid versions. 101 | * 102 | * @return A new \c Runtime object. 103 | */ 104 | function Runtime(name, versionRange) 105 | { 106 | this.name = name; 107 | this.versionRange = versionRange; 108 | } 109 | 110 | /** 111 | * @class Extension 112 | * Encapsulates a CEP-based extension to an Adobe application. 113 | * 114 | * @param id The unique identifier of this extension. 115 | * @param name The localizable display name of this extension. 116 | * @param mainPath The path of the "index.html" file. 117 | * @param basePath The base path of this extension. 118 | * @param windowType The window type of the main window of this extension. 119 | Valid values are defined by \c #CSXSWindowType. 120 | * @param width The default width in pixels of the main window of this extension. 121 | * @param height The default height in pixels of the main window of this extension. 122 | * @param minWidth The minimum width in pixels of the main window of this extension. 123 | * @param minHeight The minimum height in pixels of the main window of this extension. 124 | * @param maxWidth The maximum width in pixels of the main window of this extension. 125 | * @param maxHeight The maximum height in pixels of the main window of this extension. 126 | * @param defaultExtensionDataXml The extension data contained in the default \c ExtensionDispatchInfo section of the extension manifest. 127 | * @param specialExtensionDataXml The extension data contained in the application-specific \c ExtensionDispatchInfo section of the extension manifest. 128 | * @param requiredRuntimeList An array of \c Runtime objects for runtimes required by this extension. 129 | * @param isAutoVisible True if this extension is visible on loading. 130 | * @param isPluginExtension True if this extension has been deployed in the Plugins folder of the host application. 131 | * 132 | * @return A new \c Extension object. 133 | */ 134 | function Extension(id, name, mainPath, basePath, windowType, width, height, minWidth, minHeight, maxWidth, maxHeight, 135 | defaultExtensionDataXml, specialExtensionDataXml, requiredRuntimeList, isAutoVisible, isPluginExtension) 136 | { 137 | this.id = id; 138 | this.name = name; 139 | this.mainPath = mainPath; 140 | this.basePath = basePath; 141 | this.windowType = windowType; 142 | this.width = width; 143 | this.height = height; 144 | this.minWidth = minWidth; 145 | this.minHeight = minHeight; 146 | this.maxWidth = maxWidth; 147 | this.maxHeight = maxHeight; 148 | this.defaultExtensionDataXml = defaultExtensionDataXml; 149 | this.specialExtensionDataXml = specialExtensionDataXml; 150 | this.requiredRuntimeList = requiredRuntimeList; 151 | this.isAutoVisible = isAutoVisible; 152 | this.isPluginExtension = isPluginExtension; 153 | } 154 | 155 | /** 156 | * @class CSEvent 157 | * A standard JavaScript event, the base class for CEP events. 158 | * 159 | * @param type The name of the event type. 160 | * @param scope The scope of event, can be "GLOBAL" or "APPLICATION". 161 | * @param appId The unique identifier of the application that generated the event. 162 | * @param extensionId The unique identifier of the extension that generated the event. 163 | * 164 | * @return A new \c CSEvent object 165 | */ 166 | function CSEvent(type, scope, appId, extensionId) 167 | { 168 | this.type = type; 169 | this.scope = scope; 170 | this.appId = appId; 171 | this.extensionId = extensionId; 172 | } 173 | 174 | /** Event-specific data. */ 175 | CSEvent.prototype.data = ""; 176 | 177 | /** 178 | * @class SystemPath 179 | * Stores operating-system-specific location constants for use in the 180 | * \c #CSInterface.getSystemPath() method. 181 | * @return A new \c SystemPath object. 182 | */ 183 | function SystemPath() 184 | { 185 | } 186 | 187 | /** The path to user data. */ 188 | SystemPath.USER_DATA = "userData"; 189 | 190 | /** The path to common files for Adobe applications. */ 191 | SystemPath.COMMON_FILES = "commonFiles"; 192 | 193 | /** The path to the user's default document folder. */ 194 | SystemPath.MY_DOCUMENTS = "myDocuments"; 195 | 196 | /** @deprecated. Use \c #SystemPath.Extension. */ 197 | SystemPath.APPLICATION = "application"; 198 | 199 | /** The path to current extension. */ 200 | SystemPath.EXTENSION = "extension"; 201 | 202 | /** The path to hosting application's executable. */ 203 | SystemPath.HOST_APPLICATION = "hostApplication"; 204 | 205 | /** 206 | * @class ColorType 207 | * Stores color-type constants. 208 | */ 209 | function ColorType() 210 | { 211 | } 212 | 213 | /** RGB color type. */ 214 | ColorType.RGB = "rgb"; 215 | 216 | /** Gradient color type. */ 217 | ColorType.GRADIENT = "gradient"; 218 | 219 | /** Null color type. */ 220 | ColorType.NONE = "none"; 221 | 222 | /** 223 | * @class RGBColor 224 | * Stores an RGB color with red, green, blue, and alpha values. 225 | * All values are in the range [0.0 to 255.0]. Invalid numeric values are 226 | * converted to numbers within this range. 227 | * 228 | * @param red The red value, in the range [0.0 to 255.0]. 229 | * @param green The green value, in the range [0.0 to 255.0]. 230 | * @param blue The blue value, in the range [0.0 to 255.0]. 231 | * @param alpha The alpha (transparency) value, in the range [0.0 to 255.0]. 232 | * The default, 255.0, means that the color is fully opaque. 233 | * 234 | * @return A new RGBColor object. 235 | */ 236 | function RGBColor(red, green, blue, alpha) 237 | { 238 | this.red = red; 239 | this.green = green; 240 | this.blue = blue; 241 | this.alpha = alpha; 242 | } 243 | 244 | /** 245 | * @class Direction 246 | * A point value in which the y component is 0 and the x component 247 | * is positive or negative for a right or left direction, 248 | * or the x component is 0 and the y component is positive or negative for 249 | * an up or down direction. 250 | * 251 | * @param x The horizontal component of the point. 252 | * @param y The vertical component of the point. 253 | * 254 | * @return A new \c Direction object. 255 | */ 256 | function Direction(x, y) 257 | { 258 | this.x = x; 259 | this.y = y; 260 | } 261 | 262 | /** 263 | * @class GradientStop 264 | * Stores gradient stop information. 265 | * 266 | * @param offset The offset of the gradient stop, in the range [0.0 to 1.0]. 267 | * @param rgbColor The color of the gradient at this point, an \c #RGBColor object. 268 | * 269 | * @return GradientStop object. 270 | */ 271 | function GradientStop(offset, rgbColor) 272 | { 273 | this.offset = offset; 274 | this.rgbColor = rgbColor; 275 | } 276 | 277 | /** 278 | * @class GradientColor 279 | * Stores gradient color information. 280 | * 281 | * @param type The gradient type, must be "linear". 282 | * @param direction A \c #Direction object for the direction of the gradient 283 | (up, down, right, or left). 284 | * @param numStops The number of stops in the gradient. 285 | * @param gradientStopList An array of \c #GradientStop objects. 286 | * 287 | * @return A new \c GradientColor object. 288 | */ 289 | function GradientColor(type, direction, numStops, arrGradientStop) 290 | { 291 | this.type = type; 292 | this.direction = direction; 293 | this.numStops = numStops; 294 | this.arrGradientStop = arrGradientStop; 295 | } 296 | 297 | /** 298 | * @class UIColor 299 | * Stores color information, including the type, anti-alias level, and specific color 300 | * values in a color object of an appropriate type. 301 | * 302 | * @param type The color type, 1 for "rgb" and 2 for "gradient". 303 | The supplied color object must correspond to this type. 304 | * @param antialiasLevel The anti-alias level constant. 305 | * @param color A \c #RGBColor or \c #GradientColor object containing specific color information. 306 | * 307 | * @return A new \c UIColor object. 308 | */ 309 | function UIColor(type, antialiasLevel, color) 310 | { 311 | this.type = type; 312 | this.antialiasLevel = antialiasLevel; 313 | this.color = color; 314 | } 315 | 316 | /** 317 | * @class AppSkinInfo 318 | * Stores window-skin properties, such as color and font. All color parameter values are \c #UIColor objects except that systemHighlightColor is \c #RGBColor object. 319 | * 320 | * @param baseFontFamily The base font family of the application. 321 | * @param baseFontSize The base font size of the application. 322 | * @param appBarBackgroundColor The application bar background color. 323 | * @param panelBackgroundColor The background color of the extension panel. 324 | * @param appBarBackgroundColorSRGB The application bar background color, as sRGB. 325 | * @param panelBackgroundColorSRGB The background color of the extension panel, as sRGB. 326 | * @param systemHighlightColor The highlight color of the extension panel, if provided by the host application. Otherwise, the operating-system highlight color. 327 | * 328 | * @return AppSkinInfo object. 329 | */ 330 | function AppSkinInfo(baseFontFamily, baseFontSize, appBarBackgroundColor, panelBackgroundColor, appBarBackgroundColorSRGB, panelBackgroundColorSRGB, systemHighlightColor) 331 | { 332 | this.baseFontFamily = baseFontFamily; 333 | this.baseFontSize = baseFontSize; 334 | this.appBarBackgroundColor = appBarBackgroundColor; 335 | this.panelBackgroundColor = panelBackgroundColor; 336 | this.appBarBackgroundColorSRGB = appBarBackgroundColorSRGB; 337 | this.panelBackgroundColorSRGB = panelBackgroundColorSRGB; 338 | this.systemHighlightColor = systemHighlightColor; 339 | } 340 | 341 | /** 342 | * @class HostEnvironment 343 | * Stores information about the environment in which the extension is loaded. 344 | * 345 | * @param appName The application's name. 346 | * @param appVersion The application's version. 347 | * @param appLocale The application's current license locale. 348 | * @param appUILocale The application's current UI locale. 349 | * @param appId The application's unique identifier. 350 | * @param isAppOnline True if the application is currently online. 351 | * @param appSkinInfo An \c #AppSkinInfo object containing the application's default color and font styles. 352 | * 353 | * @return A new \c HostEnvironment object. 354 | */ 355 | function HostEnvironment(appName, appVersion, appLocale, appUILocale, appId, isAppOnline, appSkinInfo) 356 | { 357 | this.appName = appName; 358 | this.appVersion = appVersion; 359 | this.appLocale = appLocale; 360 | this.appUILocale = appUILocale; 361 | this.appId = appId; 362 | this.isAppOnline = isAppOnline; 363 | this.appSkinInfo = appSkinInfo; 364 | } 365 | 366 | /** 367 | * @class HostCapabilities 368 | * Stores information about the host capabilities. 369 | * 370 | * @param EXTENDED_PANEL_MENU True if the application supports panel menu. 371 | * @param EXTENDED_PANEL_ICONS True if the application supports panel icon. 372 | * @param DELEGATE_APE_ENGINE True if the application supports delegated APE engine. 373 | * @param SUPPORT_HTML_EXTENSIONS True if the application supports HTML extensions. 374 | * @param DISABLE_FLASH_EXTENSIONS True if the application disables FLASH extensions. 375 | * 376 | * @return A new \c HostCapabilities object. 377 | */ 378 | function HostCapabilities(EXTENDED_PANEL_MENU, EXTENDED_PANEL_ICONS, DELEGATE_APE_ENGINE, SUPPORT_HTML_EXTENSIONS, DISABLE_FLASH_EXTENSIONS) 379 | { 380 | this.EXTENDED_PANEL_MENU = EXTENDED_PANEL_MENU; 381 | this.EXTENDED_PANEL_ICONS = EXTENDED_PANEL_ICONS; 382 | this.DELEGATE_APE_ENGINE = DELEGATE_APE_ENGINE; 383 | this.SUPPORT_HTML_EXTENSIONS = SUPPORT_HTML_EXTENSIONS; 384 | this.DISABLE_FLASH_EXTENSIONS = DISABLE_FLASH_EXTENSIONS; // Since 5.0.0 385 | } 386 | 387 | /** 388 | * @class ApiVersion 389 | * Stores current api version. 390 | * 391 | * Since 4.2.0 392 | * 393 | * @param major The major version 394 | * @param minor The minor version. 395 | * @param micro The micro version. 396 | * 397 | * @return ApiVersion object. 398 | */ 399 | function ApiVersion(major, minor, micro) 400 | { 401 | this.major = major; 402 | this.minor = minor; 403 | this.micro = micro; 404 | } 405 | 406 | /** 407 | * @class MenuItemStatus 408 | * Stores flyout menu item status 409 | * 410 | * Since 5.2.0 411 | * 412 | * @param menuItemLabel The menu item label. 413 | * @param enabled True if user wants to enable the menu item. 414 | * @param checked True if user wants to check the menu item. 415 | * 416 | * @return MenuItemStatus object. 417 | */ 418 | function MenuItemStatus(menuItemLabel, enabled, checked) 419 | { 420 | this.menuItemLabel = menuItemLabel; 421 | this.enabled = enabled; 422 | this.checked = checked; 423 | } 424 | 425 | /** 426 | * @class ContextMenuItemStatus 427 | * Stores the status of the context menu item. 428 | * 429 | * Since 5.2.0 430 | * 431 | * @param menuItemID The menu item id. 432 | * @param enabled True if user wants to enable the menu item. 433 | * @param checked True if user wants to check the menu item. 434 | * 435 | * @return MenuItemStatus object. 436 | */ 437 | function ContextMenuItemStatus(menuItemID, enabled, checked) 438 | { 439 | this.menuItemID = menuItemID; 440 | this.enabled = enabled; 441 | this.checked = checked; 442 | } 443 | //------------------------------ CSInterface ---------------------------------- 444 | 445 | /** 446 | * @class CSInterface 447 | * This is the entry point to the CEP extensibility infrastructure. 448 | * Instantiate this object and use it to: 449 | * 454 | * 455 | * @return A new \c CSInterface object 456 | */ 457 | function CSInterface() 458 | { 459 | } 460 | 461 | /** 462 | * User can add this event listener to handle native application theme color changes. 463 | * Callback function gives extensions ability to fine-tune their theme color after the 464 | * global theme color has been changed. 465 | * The callback function should be like below: 466 | * 467 | * @example 468 | * // event is a CSEvent object, but user can ignore it. 469 | * function OnAppThemeColorChanged(event) 470 | * { 471 | * // Should get a latest HostEnvironment object from application. 472 | * var skinInfo = JSON.parse(window.__adobe_cep__.getHostEnvironment()).appSkinInfo; 473 | * // Gets the style information such as color info from the skinInfo, 474 | * // and redraw all UI controls of your extension according to the style info. 475 | * } 476 | */ 477 | CSInterface.THEME_COLOR_CHANGED_EVENT = "com.adobe.csxs.events.ThemeColorChanged"; 478 | 479 | /** The host environment data object. */ 480 | CSInterface.prototype.hostEnvironment = window.__adobe_cep__ ? JSON.parse(window.__adobe_cep__.getHostEnvironment()) : null; 481 | 482 | /** Retrieves information about the host environment in which the 483 | * extension is currently running. 484 | * 485 | * @return A \c #HostEnvironment object. 486 | */ 487 | CSInterface.prototype.getHostEnvironment = function() 488 | { 489 | this.hostEnvironment = JSON.parse(window.__adobe_cep__.getHostEnvironment()); 490 | return this.hostEnvironment; 491 | }; 492 | 493 | /** Closes this extension. */ 494 | CSInterface.prototype.closeExtension = function() 495 | { 496 | window.__adobe_cep__.closeExtension(); 497 | }; 498 | 499 | /** 500 | * Retrieves a path for which a constant is defined in the system. 501 | * 502 | * @param pathType The path-type constant defined in \c #SystemPath , 503 | * 504 | * @return The platform-specific system path string. 505 | */ 506 | CSInterface.prototype.getSystemPath = function(pathType) 507 | { 508 | var path = decodeURI(window.__adobe_cep__.getSystemPath(pathType)); 509 | var OSVersion = this.getOSInformation(); 510 | if (OSVersion.indexOf("Windows") >= 0) 511 | { 512 | path = path.replace("file:///", ""); 513 | } 514 | else if (OSVersion.indexOf("Mac") >= 0) 515 | { 516 | path = path.replace("file://", ""); 517 | } 518 | return path; 519 | }; 520 | 521 | /** 522 | * Evaluates a JavaScript script, which can use the JavaScript DOM 523 | * of the host application. 524 | * 525 | * @param script The JavaScript script. 526 | * @param callback Optional. A callback function that receives the result of execution. 527 | * If execution fails, the callback function receives the error message \c EvalScript_ErrMessage. 528 | */ 529 | CSInterface.prototype.evalScript = function(script, callback) 530 | { 531 | if(callback === null || callback === undefined) 532 | { 533 | callback = function(result){}; 534 | } 535 | window.__adobe_cep__.evalScript(script, callback); 536 | }; 537 | 538 | /** 539 | * Retrieves the unique identifier of the application. 540 | * in which the extension is currently running. 541 | * 542 | * @return The unique ID string. 543 | */ 544 | CSInterface.prototype.getApplicationID = function() 545 | { 546 | var appId = this.hostEnvironment.appId; 547 | return appId; 548 | }; 549 | 550 | /** 551 | * Retrieves host capability information for the application 552 | * in which the extension is currently running. 553 | * 554 | * @return A \c #HostCapabilities object. 555 | */ 556 | CSInterface.prototype.getHostCapabilities = function() 557 | { 558 | var hostCapabilities = JSON.parse(window.__adobe_cep__.getHostCapabilities() ); 559 | return hostCapabilities; 560 | }; 561 | 562 | /** 563 | * Triggers a CEP event programmatically. Yoy can use it to dispatch 564 | * an event of a predefined type, or of a type you have defined. 565 | * 566 | * @param event A \c CSEvent object. 567 | */ 568 | CSInterface.prototype.dispatchEvent = function(event) 569 | { 570 | if (typeof event.data == "object") 571 | { 572 | event.data = JSON.stringify(event.data); 573 | } 574 | 575 | window.__adobe_cep__.dispatchEvent(event); 576 | }; 577 | 578 | /** 579 | * Registers an interest in a CEP event of a particular type, and 580 | * assigns an event handler. 581 | * The event infrastructure notifies your extension when events of this type occur, 582 | * passing the event object to the registered handler function. 583 | * 584 | * @param type The name of the event type of interest. 585 | * @param listener The JavaScript handler function or method. 586 | * @param obj Optional, the object containing the handler method, if any. 587 | * Default is null. 588 | */ 589 | CSInterface.prototype.addEventListener = function(type, listener, obj) 590 | { 591 | window.__adobe_cep__.addEventListener(type, listener, obj); 592 | }; 593 | 594 | /** 595 | * Removes a registered event listener. 596 | * 597 | * @param type The name of the event type of interest. 598 | * @param listener The JavaScript handler function or method that was registered. 599 | * @param obj Optional, the object containing the handler method, if any. 600 | * Default is null. 601 | */ 602 | CSInterface.prototype.removeEventListener = function(type, listener, obj) 603 | { 604 | window.__adobe_cep__.removeEventListener(type, listener, obj); 605 | }; 606 | 607 | /** 608 | * Loads and launches another extension, or activates the extension if it is already loaded. 609 | * 610 | * @param extensionId The extension's unique identifier. 611 | * @param startupParams Not currently used, pass "". 612 | * 613 | * @example 614 | * To launch the extension "help" with ID "HLP" from this extension, call: 615 | * requestOpenExtension("HLP", ""); 616 | * 617 | */ 618 | CSInterface.prototype.requestOpenExtension = function(extensionId, params) 619 | { 620 | window.__adobe_cep__.requestOpenExtension(extensionId, params); 621 | }; 622 | 623 | /** 624 | * Retrieves the list of extensions currently loaded in the current host application. 625 | * The extension list is initialized once, and remains the same during the lifetime 626 | * of the CEP session. 627 | * 628 | * @param extensionIds Optional, an array of unique identifiers for extensions of interest. 629 | * If omitted, retrieves data for all extensions. 630 | * 631 | * @return Zero or more \c #Extension objects. 632 | */ 633 | CSInterface.prototype.getExtensions = function(extensionIds) 634 | { 635 | var extensionIdsStr = JSON.stringify(extensionIds); 636 | var extensionsStr = window.__adobe_cep__.getExtensions(extensionIdsStr); 637 | 638 | var extensions = JSON.parse(extensionsStr); 639 | return extensions; 640 | }; 641 | 642 | /** 643 | * Retrieves network-related preferences. 644 | * 645 | * @return A JavaScript object containing network preferences. 646 | */ 647 | CSInterface.prototype.getNetworkPreferences = function() 648 | { 649 | var result = window.__adobe_cep__.getNetworkPreferences(); 650 | var networkPre = JSON.parse(result); 651 | 652 | return networkPre; 653 | }; 654 | 655 | /** 656 | * Initializes the resource bundle for this extension with property values 657 | * for the current application and locale. 658 | * To support multiple locales, you must define a property file for each locale, 659 | * containing keyed display-string values for that locale. 660 | * See localization documentation for Extension Builder and related products. 661 | * 662 | * Keys can be in the 663 | * form key.value="localized string", for use in HTML text elements. 664 | * For example, in this input element, the localized \c key.value string is displayed 665 | * instead of the empty \c value string: 666 | * 667 | * 668 | * 669 | * @return An object containing the resource bundle information. 670 | */ 671 | CSInterface.prototype.initResourceBundle = function() 672 | { 673 | var resourceBundle = JSON.parse(window.__adobe_cep__.initResourceBundle()); 674 | var resElms = document.querySelectorAll('[data-locale]'); 675 | for (var n = 0; n < resElms.length; n++) 676 | { 677 | var resEl = resElms[n]; 678 | // Get the resource key from the element. 679 | var resKey = resEl.getAttribute('data-locale'); 680 | if (resKey) 681 | { 682 | // Get all the resources that start with the key. 683 | for (var key in resourceBundle) 684 | { 685 | if (key.indexOf(resKey) === 0) 686 | { 687 | var resValue = resourceBundle[key]; 688 | if (key.length == resKey.length) 689 | { 690 | resEl.innerHTML = resValue; 691 | } 692 | else if ('.' == key.charAt(resKey.length)) 693 | { 694 | var attrKey = key.substring(resKey.length + 1); 695 | resEl[attrKey] = resValue; 696 | } 697 | } 698 | } 699 | } 700 | } 701 | return resourceBundle; 702 | }; 703 | 704 | /** 705 | * Writes installation information to a file. 706 | * 707 | * @return The file path. 708 | */ 709 | CSInterface.prototype.dumpInstallationInfo = function() 710 | { 711 | return window.__adobe_cep__.dumpInstallationInfo(); 712 | }; 713 | 714 | /** 715 | * Retrieves version information for the current Operating System, 716 | * See http://www.useragentstring.com/pages/Chrome/ for Chrome \c navigator.userAgent values. 717 | * 718 | * @return A string containing the OS version, or "unknown Operation System". 719 | * If user customizes the User Agent by setting CEF command parameter "--user-agent", only 720 | * "Mac OS X" or "Windows" will be returned. 721 | */ 722 | CSInterface.prototype.getOSInformation = function() 723 | { 724 | var userAgent = navigator.userAgent; 725 | 726 | if ((navigator.platform == "Win32") || (navigator.platform == "Windows")) 727 | { 728 | var winVersion = "Windows"; 729 | var winBit = ""; 730 | if (userAgent.indexOf("Windows") > -1) 731 | { 732 | if (userAgent.indexOf("Windows NT 5.0") > -1) 733 | { 734 | winVersion = "Windows 2000"; 735 | } 736 | else if (userAgent.indexOf("Windows NT 5.1") > -1) 737 | { 738 | winVersion = "Windows XP"; 739 | } 740 | else if (userAgent.indexOf("Windows NT 5.2") > -1) 741 | { 742 | winVersion = "Windows Server 2003"; 743 | } 744 | else if (userAgent.indexOf("Windows NT 6.0") > -1) 745 | { 746 | winVersion = "Windows Vista"; 747 | } 748 | else if (userAgent.indexOf("Windows NT 6.1") > -1) 749 | { 750 | winVersion = "Windows 7"; 751 | } 752 | else if (userAgent.indexOf("Windows NT 6.2") > -1) 753 | { 754 | winVersion = "Windows 8"; 755 | } 756 | else if (userAgent.indexOf("Windows NT 6.3") > -1) 757 | { 758 | winVersion = "Windows 8.1"; 759 | } 760 | else if (userAgent.indexOf("Windows NT 10") > -1) 761 | { 762 | winVersion = "Windows 10"; 763 | } 764 | 765 | if (userAgent.indexOf("WOW64") > -1 || userAgent.indexOf("Win64") > -1) 766 | { 767 | winBit = " 64-bit"; 768 | } 769 | else 770 | { 771 | winBit = " 32-bit"; 772 | } 773 | } 774 | 775 | return winVersion + winBit; 776 | } 777 | else if ((navigator.platform == "MacIntel") || (navigator.platform == "Macintosh")) 778 | { 779 | var result = "Mac OS X"; 780 | 781 | if (userAgent.indexOf("Mac OS X") > -1) 782 | { 783 | result = userAgent.substring(userAgent.indexOf("Mac OS X"), userAgent.indexOf(")")); 784 | result = result.replace(/_/g, "."); 785 | } 786 | 787 | return result; 788 | } 789 | 790 | return "Unknown Operation System"; 791 | }; 792 | 793 | /** 794 | * Opens a page in the default system browser. 795 | * 796 | * Since 4.2.0 797 | * 798 | * @param url The URL of the page/file to open, or the email address. 799 | * Must use HTTP/HTTPS/file/mailto protocol. For example: 800 | * "http://www.adobe.com" 801 | * "https://github.com" 802 | * "file:///C:/log.txt" 803 | * "mailto:test@adobe.com" 804 | * 805 | * @return One of these error codes:\n 806 | * \n 812 | */ 813 | CSInterface.prototype.openURLInDefaultBrowser = function(url) 814 | { 815 | return cep.util.openURLInDefaultBrowser(url); 816 | }; 817 | 818 | /** 819 | * Retrieves extension ID. 820 | * 821 | * Since 4.2.0 822 | * 823 | * @return extension ID. 824 | */ 825 | CSInterface.prototype.getExtensionID = function() 826 | { 827 | return window.__adobe_cep__.getExtensionId(); 828 | }; 829 | 830 | /** 831 | * Retrieves the scale factor of screen. 832 | * On Windows platform, the value of scale factor might be different from operating system's scale factor, 833 | * since host application may use its self-defined scale factor. 834 | * 835 | * Since 4.2.0 836 | * 837 | * @return One of the following float number. 838 | * \n 843 | */ 844 | CSInterface.prototype.getScaleFactor = function() 845 | { 846 | return window.__adobe_cep__.getScaleFactor(); 847 | }; 848 | 849 | /** 850 | * Set a handler to detect any changes of scale factor. This only works on Mac. 851 | * 852 | * Since 4.2.0 853 | * 854 | * @param handler The function to be called when scale factor is changed. 855 | * 856 | */ 857 | CSInterface.prototype.setScaleFactorChangedHandler = function(handler) 858 | { 859 | window.__adobe_cep__.setScaleFactorChangedHandler(handler); 860 | }; 861 | 862 | /** 863 | * Retrieves current API version. 864 | * 865 | * Since 4.2.0 866 | * 867 | * @return ApiVersion object. 868 | * 869 | */ 870 | CSInterface.prototype.getCurrentApiVersion = function() 871 | { 872 | var apiVersion = JSON.parse(window.__adobe_cep__.getCurrentApiVersion()); 873 | return apiVersion; 874 | }; 875 | 876 | /** 877 | * Set panel flyout menu by an XML. 878 | * 879 | * Since 5.2.0 880 | * 881 | * Register a callback function for "com.adobe.csxs.events.flyoutMenuClicked" to get notified when a 882 | * menu item is clicked. 883 | * The "data" attribute of event is an object which contains "menuId" and "menuName" attributes. 884 | * 885 | * Register callback functions for "com.adobe.csxs.events.flyoutMenuOpened" and "com.adobe.csxs.events.flyoutMenuClosed" 886 | * respectively to get notified when flyout menu is opened or closed. 887 | * 888 | * @param menu A XML string which describes menu structure. 889 | * An example menu XML: 890 | * 891 | * 892 | * 893 | * 894 | * 895 | * 896 | * 897 | * 898 | * 899 | * 900 | * 901 | * 902 | */ 903 | CSInterface.prototype.setPanelFlyoutMenu = function(menu) 904 | { 905 | if ("string" != typeof menu) 906 | { 907 | return; 908 | } 909 | 910 | window.__adobe_cep__.invokeSync("setPanelFlyoutMenu", menu); 911 | }; 912 | 913 | /** 914 | * Updates a menu item in the extension window's flyout menu, by setting the enabled 915 | * and selection status. 916 | * 917 | * Since 5.2.0 918 | * 919 | * @param menuItemLabel The menu item label. 920 | * @param enabled True to enable the item, false to disable it (gray it out). 921 | * @param checked True to select the item, false to deselect it. 922 | * 923 | * @return false when the host application does not support this functionality (HostCapabilities.EXTENDED_PANEL_MENU is false). 924 | * Fails silently if menu label is invalid. 925 | * 926 | * @see HostCapabilities.EXTENDED_PANEL_MENU 927 | */ 928 | CSInterface.prototype.updatePanelMenuItem = function(menuItemLabel, enabled, checked) 929 | { 930 | var ret = false; 931 | if (this.getHostCapabilities().EXTENDED_PANEL_MENU) 932 | { 933 | var itemStatus = new MenuItemStatus(menuItemLabel, enabled, checked); 934 | ret = window.__adobe_cep__.invokeSync("updatePanelMenuItem", JSON.stringify(itemStatus)); 935 | } 936 | return ret; 937 | }; 938 | 939 | 940 | /** 941 | * Set context menu by XML string. 942 | * 943 | * Since 5.2.0 944 | * 945 | * There are a number of conventions used to communicate what type of menu item to create and how it should be handled. 946 | * - an item without menu ID or menu name is disabled and is not shown. 947 | * - if the item name is "---" (three hyphens) then it is treated as a separator. The menu ID in this case will always be NULL. 948 | * - Checkable attribute takes precedence over Checked attribute. 949 | * - a PNG icon. For optimal display results please supply a 16 x 16px icon as larger dimensions will increase the size of the menu item. 950 | The Chrome extension contextMenus API was taken as a reference. 951 | https://developer.chrome.com/extensions/contextMenus 952 | * - the items with icons and checkable items cannot coexist on the same menu level. The former take precedences over the latter. 953 | * 954 | * @param menu A XML string which describes menu structure. 955 | * @param callback The callback function which is called when a menu item is clicked. The only parameter is the returned ID of clicked menu item. 956 | * 957 | * @description An example menu XML: 958 | * 959 | * 960 | * 961 | * 962 | * 963 | * 964 | * 965 | * 966 | * 967 | * 968 | * 969 | */ 970 | CSInterface.prototype.setContextMenu = function(menu, callback) 971 | { 972 | if ("string" != typeof menu) 973 | { 974 | return; 975 | } 976 | 977 | window.__adobe_cep__.invokeAsync("setContextMenu", menu, callback); 978 | }; 979 | 980 | /** 981 | * Set context menu by JSON string. 982 | * 983 | * Since 6.0.0 984 | * 985 | * There are a number of conventions used to communicate what type of menu item to create and how it should be handled. 986 | * - an item without menu ID or menu name is disabled and is not shown. 987 | * - if the item label is "---" (three hyphens) then it is treated as a separator. The menu ID in this case will always be NULL. 988 | * - Checkable attribute takes precedence over Checked attribute. 989 | * - a PNG icon. For optimal display results please supply a 16 x 16px icon as larger dimensions will increase the size of the menu item. 990 | The Chrome extension contextMenus API was taken as a reference. 991 | * - the items with icons and checkable items cannot coexist on the same menu level. The former take precedences over the latter. 992 | https://developer.chrome.com/extensions/contextMenus 993 | * 994 | * @param menu A JSON string which describes menu structure. 995 | * @param callback The callback function which is called when a menu item is clicked. The only parameter is the returned ID of clicked menu item. 996 | * 997 | * @description An example menu JSON: 998 | * 999 | * { 1000 | * "menu": [ 1001 | * { 1002 | * "id": "menuItemId1", 1003 | * "label": "testExample1", 1004 | * "enabled": true, 1005 | * "checkable": true, 1006 | * "checked": false, 1007 | * "icon": "./image/small_16X16.png" 1008 | * }, 1009 | * { 1010 | * "id": "menuItemId2", 1011 | * "label": "testExample2", 1012 | * "menu": [ 1013 | * { 1014 | * "id": "menuItemId2-1", 1015 | * "label": "testExample2-1", 1016 | * "menu": [ 1017 | * { 1018 | * "id": "menuItemId2-1-1", 1019 | * "label": "testExample2-1-1", 1020 | * "enabled": false, 1021 | * "checkable": true, 1022 | * "checked": true 1023 | * } 1024 | * ] 1025 | * }, 1026 | * { 1027 | * "id": "menuItemId2-2", 1028 | * "label": "testExample2-2", 1029 | * "enabled": true, 1030 | * "checkable": true, 1031 | * "checked": true 1032 | * } 1033 | * ] 1034 | * }, 1035 | * { 1036 | * "label": "---" 1037 | * }, 1038 | * { 1039 | * "id": "menuItemId3", 1040 | * "label": "testExample3", 1041 | * "enabled": false, 1042 | * "checkable": true, 1043 | * "checked": false 1044 | * } 1045 | * ] 1046 | * } 1047 | * 1048 | */ 1049 | CSInterface.prototype.setContextMenuByJSON = function(menu, callback) 1050 | { 1051 | if ("string" != typeof menu) 1052 | { 1053 | return; 1054 | } 1055 | 1056 | window.__adobe_cep__.invokeAsync("setContextMenuByJSON", menu, callback); 1057 | }; 1058 | 1059 | /** 1060 | * Updates a context menu item by setting the enabled and selection status. 1061 | * 1062 | * Since 5.2.0 1063 | * 1064 | * @param menuItemID The menu item ID. 1065 | * @param enabled True to enable the item, false to disable it (gray it out). 1066 | * @param checked True to select the item, false to deselect it. 1067 | */ 1068 | CSInterface.prototype.updateContextMenuItem = function(menuItemID, enabled, checked) 1069 | { 1070 | var itemStatus = new ContextMenuItemStatus(menuItemID, enabled, checked); 1071 | ret = window.__adobe_cep__.invokeSync("updateContextMenuItem", JSON.stringify(itemStatus)); 1072 | }; 1073 | 1074 | /** 1075 | * Get the visibility status of an extension window. 1076 | * 1077 | * Since 6.0.0 1078 | * 1079 | * @return true if the extension window is visible; false if the extension window is hidden. 1080 | */ 1081 | CSInterface.prototype.isWindowVisible = function() 1082 | { 1083 | return window.__adobe_cep__.invokeSync("isWindowVisible", ""); 1084 | }; 1085 | 1086 | /** 1087 | * Resize extension's content to the specified dimensions. 1088 | * 1. Works with modal and modeless extensions in all Adobe products. 1089 | * 2. Extension's manifest min/max size constraints apply and take precedence. 1090 | * 3. For panel extensions 1091 | * 3.1 This works in all Adobe products except: 1092 | * * Premiere Pro 1093 | * * Prelude 1094 | * * After Effects 1095 | * 3.2 When the panel is in certain states (especially when being docked), 1096 | * it will not change to the desired dimensions even when the 1097 | * specified size satisfies min/max constraints. 1098 | * 1099 | * Since 6.0.0 1100 | * 1101 | * @param width The new width 1102 | * @param height The new height 1103 | */ 1104 | CSInterface.prototype.resizeContent = function(width, height) 1105 | { 1106 | window.__adobe_cep__.resizeContent(width, height); 1107 | }; 1108 | 1109 | /** 1110 | * Register the invalid certificate callback for an extension. 1111 | * This callback will be triggered when the extension tries to access the web site that contains the invalid certificate on the main frame. 1112 | * But if the extension does not call this function and tries to access the web site containing the invalid certificate, a default error page will be shown. 1113 | * 1114 | * Since 6.1.0 1115 | * 1116 | * @param callback the callback function 1117 | */ 1118 | CSInterface.prototype.registerInvalidCertificateCallback = function(callback) 1119 | { 1120 | return window.__adobe_cep__.registerInvalidCertificateCallback(callback); 1121 | }; 1122 | 1123 | /** 1124 | * Register an interest in some key events to prevent them from being sent to the host application. 1125 | * 1126 | * This function works with modeless extensions and panel extensions. 1127 | * Generally all the key events will be sent to the host application for these two extensions if the current focused element 1128 | * is not text input or dropdown, 1129 | * If you want to intercept some key events and want them to be handled in the extension, please call this function 1130 | * in advance to prevent them being sent to the host application. 1131 | * 1132 | * Since 6.1.0 1133 | * 1134 | * @param keyEventsInterest A JSON string describing those key events you are interested in. A null object or 1135 | an empty string will lead to removing the interest 1136 | * 1137 | * This JSON string should be an array, each object has following keys: 1138 | * 1139 | * keyCode: [Required] represents an OS system dependent virtual key code identifying 1140 | * the unmodified value of the pressed key. 1141 | * ctrlKey: [optional] a Boolean that indicates if the control key was pressed (true) or not (false) when the event occurred. 1142 | * altKey: [optional] a Boolean that indicates if the alt key was pressed (true) or not (false) when the event occurred. 1143 | * shiftKey: [optional] a Boolean that indicates if the shift key was pressed (true) or not (false) when the event occurred. 1144 | * metaKey: [optional] (Mac Only) a Boolean that indicates if the Meta key was pressed (true) or not (false) when the event occurred. 1145 | * On Macintosh keyboards, this is the command key. To detect Windows key on Windows, please use keyCode instead. 1146 | * An example JSON string: 1147 | * 1148 | * [ 1149 | * { 1150 | * "keyCode": 48 1151 | * }, 1152 | * { 1153 | * "keyCode": 123, 1154 | * "ctrlKey": true 1155 | * }, 1156 | * { 1157 | * "keyCode": 123, 1158 | * "ctrlKey": true, 1159 | * "metaKey": true 1160 | * } 1161 | * ] 1162 | * 1163 | */ 1164 | CSInterface.prototype.registerKeyEventsInterest = function(keyEventsInterest) 1165 | { 1166 | return window.__adobe_cep__.registerKeyEventsInterest(keyEventsInterest); 1167 | }; 1168 | 1169 | /** 1170 | * Set the title of the extension window. 1171 | * This function works with modal and modeless extensions in all Adobe products, and panel extensions in Photoshop, InDesign, InCopy, Illustrator, Flash Pro and Dreamweaver. 1172 | * 1173 | * Since 6.1.0 1174 | * 1175 | * @param title The window title. 1176 | */ 1177 | CSInterface.prototype.setWindowTitle = function(title) 1178 | { 1179 | window.__adobe_cep__.invokeSync("setWindowTitle", title); 1180 | }; 1181 | 1182 | /** 1183 | * Get the title of the extension window. 1184 | * This function works with modal and modeless extensions in all Adobe products, and panel extensions in Photoshop, InDesign, InCopy, Illustrator, Flash Pro and Dreamweaver. 1185 | * 1186 | * Since 6.1.0 1187 | * 1188 | * @return The window title. 1189 | */ 1190 | CSInterface.prototype.getWindowTitle = function() 1191 | { 1192 | return window.__adobe_cep__.invokeSync("getWindowTitle", ""); 1193 | }; 1194 | -------------------------------------------------------------------------------- /js/main.js: -------------------------------------------------------------------------------- 1 | /*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */ 2 | /*global $, window, location, CSInterface, SystemPath, themeManager*/ 3 | 'use strict'; 4 | 5 | function main() { 6 | //init 7 | let ffx = require(__dirname + '/js/node_modules/colorama_ffx'); 8 | 9 | let csInterface = new CSInterface(); 10 | let tab_container = document.querySelector("#gradtab-container"); 11 | let btn_addtab = document.querySelector("#btn-addtab"); 12 | let btn_deltab = document.querySelector("#btn-deltab"); 13 | let btn_changecolor = document.querySelector("#btn-changecolor"); 14 | let btn_apply = document.querySelector("#btn-apply"); 15 | let gradient = document.querySelector("#grad"); 16 | let tab_table = document.querySelector("#tab-table"); 17 | let pos_input = document.querySelector("#pos-input"); 18 | let btn_table = document.querySelector("#btn-table"); 19 | let btn_help = document.querySelector("#btn-help"); 20 | 21 | let tabs; 22 | let tab_colors; 23 | let tab_positions; 24 | 25 | const tab_width = 10; //in px, check styles.css > .gradtab > width 26 | 27 | const max_tab_count = 64; 28 | 29 | const extremity_soft_limit = 0.005; 30 | 31 | let root_path, picker_aex_path; 32 | switch (process.platform) { 33 | case 'win32': 34 | root_path = csInterface.getSystemPath(SystemPath.EXTENSION).replace(new RegExp('\/', 'g'), '\\\\') + '\\\\'; 35 | picker_aex_path = `lib:${root_path}AEColorPicker.aex`; 36 | break; 37 | case 'darwin': 38 | root_path = csInterface.getSystemPath(SystemPath.EXTENSION) + '/'; 39 | picker_aex_path = `lib:${root_path}AEColorPicker.plugin`; 40 | break; 41 | default: 42 | alert("Platform Error!"); 43 | break; 44 | } 45 | 46 | const ffxPath = ffx.outPath; 47 | 48 | let selected_tab; 49 | 50 | let last_selected_color = "FF0000"; 51 | 52 | update_tab_data(); 53 | 54 | tabs.forEach(init_tab); 55 | init_tab_dragging(); 56 | init_btn_addtab(); 57 | init_btn_deltab(); 58 | init_btn_changecolor(); 59 | init_btn_apply(); 60 | init_btn_table(); 61 | init_btn_help(); 62 | init_pos_input(); 63 | 64 | themeManager.init(); 65 | 66 | update_grad(tab_colors, tab_positions); 67 | 68 | 69 | // helpers 70 | function update_grad(colors, positions) { 71 | let grad_str = "linear-gradient(to right, "; 72 | 73 | var i; 74 | for (i = 0;; i++) { 75 | if (i != tabs.length - 1) { 76 | grad_str += `#${colors[i]} ${positions[i]*100}%, `; 77 | } else { 78 | grad_str += `#${colors[i]} ${positions[i]*100}%)`; 79 | break; 80 | } 81 | } 82 | 83 | gradient.style.background = grad_str; 84 | 85 | update_table(); 86 | } 87 | 88 | function update_table() { 89 | Array.from(tab_table.children[0].rows).forEach((e) => e.remove()); 90 | let rows = tabs.map((e, i) => tab_table.insertRow(0)); 91 | rows.reverse().forEach((r, i) => { 92 | if (i === tabs.indexOf(selected_tab)) { 93 | r.classList.add("tr-selected"); 94 | } 95 | let cell1 = r.insertCell(0); 96 | let cell2 = r.insertCell(1); 97 | let cell3 = r.insertCell(2); 98 | cell1.innerHTML = i; 99 | cell2.innerHTML = (tab_positions[i] * 100).toFixed(2) + "%"; 100 | cell3.innerHTML = tab_colors[i]; 101 | 102 | cell3.style.position = "relative"; 103 | let preview_block = document.createElement("div"); 104 | preview_block.classList.add("preview-block"); 105 | preview_block.style.backgroundColor = `#${tab_colors[i]}`; 106 | cell3.appendChild(preview_block); 107 | }); 108 | rows.forEach((e, i) => e.addEventListener("click", function() { 109 | update_selection(tabs[i]); 110 | update_grad(tab_colors, tab_positions); 111 | })); 112 | rows.forEach((e, i) => e.addEventListener("dblclick", function() { 113 | csInterface.evalScript( 114 | `pickColor(${parseInt(selected_tab.dataset.color, 16)}, \"${picker_aex_path}\");`, 115 | function(result) { 116 | selected_tab.dataset.color = last_selected_color = Number(result).toString(16).toUpperCase().padStart(6, '0'); 117 | tab_set_color(selected_tab); 118 | update_tab_data(); 119 | update_grad(tab_colors, tab_positions); 120 | }); 121 | })); 122 | } 123 | 124 | function update_tab_data() { 125 | tabs = Array.from(document.querySelectorAll(".gradtab")); 126 | tabs.sort((a, b) => (a.dataset.pos - b.dataset.pos)); 127 | tab_colors = tabs.map((tab) => tab.dataset.color); 128 | tab_positions = tabs.map((tab) => tab.dataset.pos); 129 | } 130 | 131 | function update_selection(tab) { 132 | Array.from(tab_table.rows).forEach((item) => item.classList.remove("tr-selected")); 133 | tabs.forEach((i_tab) => { 134 | i_tab.classList.remove("selected"); 135 | }); 136 | if (tab) { 137 | selected_tab = tab; 138 | tab.classList.add("selected"); 139 | last_selected_color = tab.dataset.color; 140 | 141 | tab_table.rows[tabs.indexOf(tab)].classList.add("tr-selected"); 142 | if ((selected_tab.id === "first-tab") || (selected_tab.id === "last-tab")) { 143 | pos_input.disabled = true; 144 | } else { 145 | pos_input.disabled = false; 146 | } 147 | pos_input.value = tab.dataset.pos; 148 | } else { 149 | selected_tab = null; 150 | pos_input.value = ""; 151 | pos_input.disabled = true; 152 | } 153 | } 154 | 155 | function compute_tab_pos(percentage) { 156 | return `calc(${percentage*100}% - ${tab_width/2}px)`; 157 | } 158 | 159 | function tab_set_color(tab) { 160 | tab.style.backgroundColor = `#${tab.dataset.color}`; 161 | } 162 | 163 | function update_tab_pos(tab, pos) { 164 | if ((selected_tab.id === "first-tab") || (selected_tab.id === "last-tab")) 165 | return; 166 | tab.style.left = compute_tab_pos(pos); 167 | pos_input.value = tab.dataset.pos = pos; 168 | update_tab_data(); 169 | update_grad(tab_colors, tab_positions); 170 | } 171 | 172 | //init functions 173 | function init_tab(tab) { 174 | tab.addEventListener("mousedown", function() { 175 | update_selection(this); 176 | }); 177 | tab.style.left = compute_tab_pos(tab.dataset.pos); 178 | if (tab.dataset.color) 179 | tab_set_color(tab); 180 | tab.addEventListener("dblclick", function() { 181 | csInterface.evalScript( 182 | `pickColor(${parseInt(selected_tab.dataset.color, 16)}, \"${picker_aex_path}\");`, 183 | function(result) { 184 | selected_tab.dataset.color = last_selected_color = Number(result).toString(16).toUpperCase().padStart(6, '0'); 185 | tab_set_color(selected_tab); 186 | update_tab_data(); 187 | update_grad(tab_colors, tab_positions); 188 | }); 189 | }); 190 | } 191 | 192 | function init_tab_dragging() { 193 | tab_container.addEventListener("mousedown", function(e) { 194 | if (e.target === this) { 195 | update_selection(null); 196 | return; 197 | }; 198 | let grad_offset = calc_abs_left(document.querySelector("#first-tab")); 199 | let grad_length = calc_abs_left(document.querySelector("#last-tab")) - grad_offset; 200 | 201 | window.onmousemove = function(emove) { 202 | if (selected_tab && !(selected_tab.id === "first-tab") && !(selected_tab.id === "last-tab")) { 203 | let new_tab_pos = Math.min(Math.max(extremity_soft_limit, (emove.clientX - grad_offset) / grad_length), 1 - extremity_soft_limit); 204 | update_tab_pos(selected_tab, new_tab_pos); 205 | } 206 | }; 207 | 208 | window.addEventListener("mouseup", function() { 209 | window.onmousemove = null; 210 | }); 211 | }); 212 | } 213 | 214 | function init_btn_addtab() { 215 | btn_addtab.addEventListener("click", function() { 216 | if (!(tabs.length < max_tab_count)) { 217 | csInterface.evalScript('alert("Max amount of tabs reached!");'); 218 | return; 219 | } 220 | let tab = document.createElement("span"); 221 | tab.classList.add("gradtab"); 222 | tab.dataset.color = last_selected_color; 223 | tab.dataset.pos = (tab_positions[0] + tab_positions[1]) / 2; 224 | init_tab(tab); 225 | tab_container.appendChild(tab); 226 | update_tab_data(); 227 | update_grad(tab_colors, tab_positions); 228 | update_selection(tab); 229 | }); 230 | } 231 | 232 | function init_btn_deltab() { 233 | btn_deltab.addEventListener("click", function() { 234 | if (!selected_tab) { 235 | csInterface.evalScript('alert("No tab selected!");'); 236 | return; 237 | } 238 | if (selected_tab.id === "last-tab" || selected_tab.id === "first-tab") { 239 | csInterface.evalScript('alert("This tab cannot be deleted!");'); 240 | return; 241 | } 242 | selected_tab.remove(); 243 | update_selection(null); 244 | update_tab_data(); 245 | update_grad(tab_colors, tab_positions); 246 | }); 247 | } 248 | 249 | function init_btn_changecolor() { 250 | btn_changecolor.addEventListener("click", function() { 251 | if (!selected_tab) { 252 | csInterface.evalScript('alert("No tab selected!");'); 253 | return; 254 | } 255 | 256 | csInterface.evalScript( 257 | `pickColor(${parseInt(selected_tab.dataset.color, 16)}, \"${picker_aex_path}\");`, 258 | function(result) { 259 | selected_tab.dataset.color = last_selected_color = Number(result).toString(16).toUpperCase().padStart(6, '0'); 260 | tab_set_color(selected_tab); 261 | update_tab_data(); 262 | update_grad(tab_colors, tab_positions); 263 | }); 264 | }); 265 | } 266 | 267 | function init_btn_apply() { 268 | btn_apply.addEventListener("click", function() { 269 | csInterface.evalScript('queryColorama();', function(result) { 270 | ffx.writeColors(tab_colors, tab_positions); 271 | csInterface.evalScript(`applyColorama(\"${ffxPath}\", ${result.toString()});`); 272 | }); 273 | }); 274 | } 275 | 276 | function init_pos_input() { 277 | pos_input.disabled = true; 278 | pos_input.addEventListener("focusout", function() { 279 | update_tab_pos(selected_tab, Math.max(Math.min(this.value, 1 - extremity_soft_limit), extremity_soft_limit)); 280 | }); 281 | pos_input.addEventListener("keyup", function(e) { 282 | if (e.keyCode === 13) { 283 | e.preventDefault(); 284 | update_tab_pos(selected_tab, Math.max(Math.min(this.value, 1 - extremity_soft_limit), extremity_soft_limit)); 285 | } 286 | }); 287 | } 288 | 289 | function init_btn_help() { 290 | btn_help.addEventListener("click", function() { 291 | csInterface.evalScript('help();'); 292 | }); 293 | } 294 | 295 | function init_btn_table() { 296 | btn_table.addEventListener("click", function() { 297 | this.classList.toggle("pushed"); 298 | tab_table.parentElement.classList.toggle("hidden"); 299 | }); 300 | } 301 | 302 | //misc helpers 303 | function calc_abs_left(elem) { 304 | let b = elem.getBoundingClientRect(); 305 | return (b.left + b.right) / 2; 306 | } 307 | } 308 | 309 | main(); -------------------------------------------------------------------------------- /js/node_modules/colorama_ffx/index.js: -------------------------------------------------------------------------------- 1 | let fs = require('fs'); 2 | let path = require('path'); 3 | 4 | const app_path = path.join(__dirname, '..', '..', '..'); 5 | const template_path = path.join(app_path, "template.ffx"); 6 | const out_path = (() => { 7 | const try_path = path.join(app_path, "coloramen.ffx"); 8 | 9 | const createDirRecursively = (dir) => { 10 | if (!fs.existsSync(dir)) { 11 | createDirRecursively(path.join(dir, "..")); 12 | fs.mkdirSync(dir); 13 | } 14 | } 15 | 16 | switch (process.platform) { 17 | case 'win32': 18 | try { 19 | fs.closeSync(fs.openSync(path.join(app_path, "template.ffx"), 'a')); 20 | return try_path.replace(new RegExp('\\\\', 'g'), '\\\\'); 21 | } catch (err) { 22 | const fallback = path.join(process.env.APPDATA, "Adobe", "CEP", "extensions", "com.lachrymalf.coloramen", "coloramen.ffx"); 23 | 24 | if (!fs.existsSync(path.dirname(fallback))) { 25 | createDirRecursively(path.dirname(fallback)); 26 | } 27 | 28 | return fallback.replace(new RegExp('\\\\', 'g'), '\\\\'); 29 | } 30 | case 'darwin': 31 | try { 32 | fs.accessSync(try_path, fs.constants.W_OK); 33 | return try_path; 34 | } catch (err) { 35 | const fallback = path.join(process.env.HOME, "Library", "Application Support", "Adobe", "CEP", "extensions", "com.lachrymalf.coloramen", "coloramen.ffx"); 36 | 37 | if (!fs.existsSync(path.dirname(fallback))) { 38 | createDirRecursively(path.dirname(fallback)); 39 | } 40 | 41 | return fallback; 42 | } 43 | default: 44 | alert("Platform Error!"); 45 | break; 46 | } 47 | })(); 48 | 49 | let try_readFileSync = (path) => { 50 | try { 51 | return fs.readFileSync(path); 52 | } catch (e) { 53 | alert(e); 54 | return null; 55 | } 56 | } 57 | 58 | const template = try_readFileSync(template_path).toString("hex"); 59 | 60 | const colors_offset = [0x0CD0, 0x2D1C]; 61 | const num_offset = [0x0ED3, 0x2F1F]; 62 | 63 | const pad_alpha = 'FF'; 64 | const key_width = 16; // number characters one definition of a key takes 65 | 66 | exports.outPath = out_path; 67 | 68 | exports.writeColors = function(colors, positions) { 69 | if (fs.existsSync(out_path)) 70 | fs.unlinkSync(out_path); 71 | 72 | let output = Array.from(template); 73 | colors.forEach((e, i) => { 74 | let out_str = (positions[i] * 0xFFFF).toString(16).split('.')[0].padStart(8, '0') + pad_alpha + e; 75 | 76 | colors_offset.forEach((z) => { 77 | Array.from(out_str).forEach((f, j) => { 78 | output[z * 2 + j + i * key_width] = f; 79 | }); 80 | }); 81 | }); 82 | 83 | let num_str = colors.length.toString(16).padStart(2, '0'); 84 | Array.from(num_str).forEach((e, i) => { 85 | num_offset.forEach((z) => { 86 | output[z * 2 + i] = e; 87 | }); 88 | }); 89 | let buffer = Buffer.from(output.join(''), "hex"); 90 | fs.appendFileSync(out_path, buffer); 91 | } 92 | -------------------------------------------------------------------------------- /js/node_modules/colorama_ffx/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "colorama_ffx", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "MIT" 12 | } -------------------------------------------------------------------------------- /js/themeManager.js: -------------------------------------------------------------------------------- 1 | /*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */ 2 | /*global window, document, CSInterface*/ 3 | 4 | 5 | /* 6 | 7 | Responsible for overwriting CSS at runtime according to CC app 8 | settings as defined by the end user. 9 | 10 | */ 11 | 12 | var themeManager = (function () { 13 | 'use strict'; 14 | 15 | /** 16 | * Convert the Color object to string in hexadecimal format; 17 | */ 18 | function toHex(color, delta) { 19 | 20 | function computeValue(value, delta) { 21 | var computedValue = !isNaN(delta) ? value + delta : value; 22 | if (computedValue < 0) { 23 | computedValue = 0; 24 | } else if (computedValue > 255) { 25 | computedValue = 255; 26 | } 27 | 28 | computedValue = Math.floor(computedValue); 29 | 30 | computedValue = computedValue.toString(16); 31 | return computedValue.length === 1 ? "0" + computedValue : computedValue; 32 | } 33 | 34 | var hex = ""; 35 | if (color) { 36 | hex = computeValue(color.red, delta) + computeValue(color.green, delta) + computeValue(color.blue, delta); 37 | } 38 | return hex; 39 | } 40 | 41 | 42 | function reverseColor(color, delta) { 43 | return toHex({ 44 | red: Math.abs(255 - color.red), 45 | green: Math.abs(255 - color.green), 46 | blue: Math.abs(255 - color.blue) 47 | }, 48 | delta); 49 | } 50 | 51 | 52 | function addRule(stylesheetId, selector, rule) { 53 | var stylesheet = document.getElementById(stylesheetId); 54 | 55 | if (stylesheet) { 56 | stylesheet = stylesheet.sheet; 57 | if (stylesheet.addRule) { 58 | stylesheet.addRule(selector, rule); 59 | } else if (stylesheet.insertRule) { 60 | stylesheet.insertRule(selector + ' { ' + rule + ' }', stylesheet.cssRules.length); 61 | } 62 | } 63 | } 64 | 65 | 66 | 67 | /** 68 | * Update the theme with the AppSkinInfo retrieved from the host product. 69 | */ 70 | function updateThemeWithAppSkinInfo(appSkinInfo) { 71 | 72 | var panelBgColor = appSkinInfo.panelBackgroundColor.color; 73 | var bgdColor = toHex(panelBgColor); 74 | 75 | var darkBgdColor = toHex(panelBgColor, 20); 76 | 77 | var fontColor = "F0F0F0"; 78 | if (panelBgColor.red > 122) { 79 | fontColor = "000000"; 80 | } 81 | var lightBgdColor = toHex(panelBgColor, -100); 82 | 83 | var styleId = "hostStyle"; 84 | 85 | addRule(styleId, ".hostElt", "background-color:" + "#" + bgdColor); 86 | addRule(styleId, ".hostElt", "font-size:" + appSkinInfo.baseFontSize + "px;"); 87 | addRule(styleId, ".hostElt", "font-family:" + appSkinInfo.baseFontFamily); 88 | addRule(styleId, ".hostElt", "color:" + "#" + fontColor); 89 | 90 | addRule(styleId, ".hostBgd", "background-color:" + "#" + bgdColor); 91 | addRule(styleId, ".hostBgdDark", "background-color: " + "#" + darkBgdColor); 92 | addRule(styleId, ".hostBgdLight", "background-color: " + "#" + lightBgdColor); 93 | addRule(styleId, ".hostFontSize", "font-size:" + appSkinInfo.baseFontSize + "px;"); 94 | addRule(styleId, ".hostFontFamily", "font-family:" + appSkinInfo.baseFontFamily); 95 | addRule(styleId, ".hostFontColor", "color:" + "#" + fontColor); 96 | 97 | addRule(styleId, ".hostFont", "font-size:" + appSkinInfo.baseFontSize + "px;"); 98 | addRule(styleId, ".hostFont", "font-family:" + appSkinInfo.baseFontFamily); 99 | addRule(styleId, ".hostFont", "color:" + "#" + fontColor); 100 | 101 | addRule(styleId, ".hostButton", "background-color:" + "#" + darkBgdColor); 102 | addRule(styleId, ".hostButton:hover", "background-color:" + "#" + bgdColor); 103 | addRule(styleId, ".hostButton:active", "background-color:" + "#" + darkBgdColor); 104 | addRule(styleId, ".hostButton", "border-color: " + "#" + lightBgdColor); 105 | 106 | } 107 | 108 | 109 | function onAppThemeColorChanged(event) { 110 | var skinInfo = JSON.parse(window.__adobe_cep__.getHostEnvironment()).appSkinInfo; 111 | updateThemeWithAppSkinInfo(skinInfo); 112 | } 113 | 114 | 115 | function init() { 116 | 117 | var csInterface = new CSInterface(); 118 | 119 | updateThemeWithAppSkinInfo(csInterface.hostEnvironment.appSkinInfo); 120 | 121 | csInterface.addEventListener(CSInterface.THEME_COLOR_CHANGED_EVENT, onAppThemeColorChanged); 122 | } 123 | 124 | return { 125 | init: init 126 | }; 127 | 128 | }()); 129 | -------------------------------------------------------------------------------- /jsx/hostscript.jsx: -------------------------------------------------------------------------------- 1 | /*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */ 2 | /*global $, Folder*/ 3 | 4 | var parameter_IDs = [2, 3, 4, 5, 6, 11, 12, 15, 16, 17, 20, 21, 22, 23, 26, 27, 29, 30]; // check ID labels 5 | var parameters = []; 6 | 7 | function getParameters() { 8 | parameters = []; //flush, shouldnt have to do this but just to be safe 9 | var i; 10 | for (i = 0; i < parameter_IDs.length; i++) { 11 | parameters.push(app.project.activeItem.selectedLayers[0].effect("Coloramen").property(parameter_IDs[i]).value); 12 | } 13 | } 14 | 15 | function setParameters() { 16 | var i; 17 | for (i = 0; i < parameter_IDs.length; i++) { 18 | app.project.activeItem.selectedLayers[0].effect("Coloramen").property(parameter_IDs[i]).setValue(parameters[i]); 19 | } 20 | parameters = []; //flush 21 | } 22 | 23 | function queryColorama() { 24 | try { 25 | var s = app.project.activeItem.selectedLayers; 26 | } catch (e) { 27 | alert("Please select a layer!"); 28 | return -1; 29 | } 30 | if (s.length == 0) { 31 | alert("Please select a layer!"); 32 | return -1; 33 | } 34 | if (s.length > 1) { 35 | alert("Please select only one layer!"); 36 | return -1; 37 | } 38 | if (s[0].effect("Coloramen")) { 39 | return true; 40 | } else { 41 | return false; 42 | } 43 | } 44 | 45 | function applyColorama(dirToFFX, effectPresent) { 46 | if (effectPresent) { 47 | focusColorama(); 48 | getParameters(); 49 | } 50 | var layer = app.project.activeItem.selectedLayers[0]; 51 | var ffx = new File(dirToFFX); 52 | app.beginUndoGroup("Apply Colorama"); 53 | layer.applyPreset(ffx); 54 | if (effectPresent) { 55 | setParameters(); 56 | } 57 | app.endUndoGroup(); 58 | } 59 | 60 | function focusColorama() { 61 | var layer = app.project.activeItem.selectedLayers[0]; 62 | app.executeCommand(2004); 63 | layer.selected = true; 64 | layer.effect("Coloramen").selected = true; // assume exists, checked through queryColorama 65 | } 66 | 67 | function pickColor(oldColor, dir) { 68 | var externalLibrary = new ExternalObject(dir); 69 | var newColor = externalLibrary.colorPicker(oldColor, "dialog_title"); 70 | if(newColor == -1){ //Returns -1 if user clicked on cancel 71 | newColor = oldColor; 72 | } 73 | return newColor; 74 | } 75 | 76 | function help() { 77 | alert("Coloramen v1.0.0\nColorama helper panel\nlachrymal.net\n2021"); 78 | } -------------------------------------------------------------------------------- /template.ffx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lachrymaLF/Coloramen/2fa9492294456c4971601573548bcbde1ee9c98a/template.ffx --------------------------------------------------------------------------------