├── .gitignore ├── Ai2Canvas.sln ├── Ai2Canvas.vcxproj ├── Ai2Canvas.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── Ai2Canvas.xcscheme ├── Info.plist ├── LICENSE ├── README.md ├── Resources ├── Ai2Canvas.r ├── Ai2Canvas.rc └── resource.h ├── Scripting └── CanvasExportScript.jsx ├── Source ├── Ai2CanvasID.h ├── Ai2CanvasPlugin.cpp ├── Ai2CanvasPlugin.h ├── Ai2CanvasSuites.cpp ├── Ai2CanvasSuites.h ├── AnimationClock.cpp ├── AnimationClock.h ├── AnimationFunction.cpp ├── AnimationFunction.h ├── Canvas.cpp ├── Canvas.h ├── CanvasCollection.cpp ├── CanvasCollection.h ├── Document.cpp ├── Document.h ├── DocumentResources.cpp ├── DocumentResources.h ├── DrawFunction.cpp ├── DrawFunction.h ├── Function.cpp ├── Function.h ├── FunctionCollection.cpp ├── FunctionCollection.h ├── Image.cpp ├── Image.h ├── ImageCollection.cpp ├── ImageCollection.h ├── Layer.cpp ├── Layer.h ├── Pattern.cpp ├── Pattern.h ├── PatternCollection.cpp ├── PatternCollection.h ├── State.cpp ├── State.h ├── Trigger.cpp ├── Trigger.h ├── Utility.cpp └── Utility.h └── plugin.pipl /.gitignore: -------------------------------------------------------------------------------- 1 | # Visual Studio 2 | 3 | Thumbs.db 4 | *.obj 5 | *.exe 6 | *.pdb 7 | *.user 8 | *.aps 9 | *.pch 10 | *.vspscc 11 | *_i.c 12 | *_p.c 13 | *.ncb 14 | *.suo 15 | *.sln.docstates 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.cache 20 | *.ilk 21 | *.log 22 | [Bb]in 23 | [Dd]ebug*/ 24 | *.lib 25 | *.sbr 26 | obj/ 27 | [Rr]elease*/ 28 | _ReSharper*/ 29 | [Tt]est[Rr]esult* 30 | *.vssscc 31 | $tf*/ 32 | ipch/ 33 | *.opensdf 34 | *.sdf 35 | *.cachefile 36 | *.exp 37 | .vs/ 38 | 39 | # Xcode 40 | .DS_Store 41 | */build/* 42 | *.pbxuser 43 | !default.pbxuser 44 | *.mode1v3 45 | !default.mode1v3 46 | *.mode2v3 47 | !default.mode2v3 48 | *.perspectivev3 49 | !default.perspectivev3 50 | xcuserdata 51 | profile 52 | *.moved-aside 53 | DerivedData 54 | .idea/ 55 | *.hmap 56 | *.xccheckout 57 | Ai2Canvas.build*/ 58 | XCBuildData -------------------------------------------------------------------------------- /Ai2Canvas.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31205.134 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ai2Canvas", "Ai2Canvas.vcxproj", "{F8D82877-059A-4454-A511-18CDDB997316}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {F8D82877-059A-4454-A511-18CDDB997316}.Debug|x64.ActiveCfg = Debug|x64 15 | {F8D82877-059A-4454-A511-18CDDB997316}.Debug|x64.Build.0 = Debug|x64 16 | {F8D82877-059A-4454-A511-18CDDB997316}.Release|x64.ActiveCfg = Release|x64 17 | {F8D82877-059A-4454-A511-18CDDB997316}.Release|x64.Build.0 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {3921AA5A-9161-493C-BD52-F230B9D04051} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Ai2Canvas.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {F8D82877-059A-4454-A511-18CDDB997316} 23 | TextFileFormat 24 | Ai2Canvas 25 | 10.0 26 | 27 | 28 | 29 | DynamicLibrary 30 | false 31 | v142 32 | 33 | 34 | DynamicLibrary 35 | false 36 | v142 37 | 38 | 39 | DynamicLibrary 40 | false 41 | v142 42 | 43 | 44 | DynamicLibrary 45 | false 46 | v142 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | <_ProjectFileVersion>10.0.40219.1 70 | ..\output\win\$(Platform)\$(Configuration)\ 71 | ..\output\objects\$(Platform)\Ai2Canvas\$(Configuration)\ 72 | true 73 | ..\output\win\$(Platform)\$(Configuration)\ 74 | ..\output\objects\$(Platform)\Ai2Canvas\$(Configuration)\ 75 | true 76 | ..\output\win\$(Platform)\$(Configuration)\ 77 | ..\output\objects\$(Platform)\Ai2Canvas\$(Configuration)\ 78 | true 79 | ..\output\win\$(Platform)\$(Configuration)\ 80 | ..\output\objects\$(Platform)\Ai2Canvas\$(Configuration)\ 81 | true 82 | AllRules.ruleset 83 | 84 | 85 | AllRules.ruleset 86 | 87 | 88 | AllRules.ruleset 89 | 90 | 91 | AllRules.ruleset 92 | 93 | 94 | .aip 95 | .aip 96 | .aip 97 | .aip 98 | $(ProjectName)$(PlatformArchitecture) 99 | $(ProjectName)$(PlatformArchitecture) 100 | $(ProjectName)$(PlatformArchitecture) 101 | $(ProjectName)$(PlatformArchitecture) 102 | 103 | 104 | 105 | _DEBUG;%(PreprocessorDefinitions) 106 | true 107 | true 108 | Win32 109 | ./TextFileFormatProject.tlb 110 | 111 | 112 | 113 | 114 | Disabled 115 | .\Source;.\Resources;..\common\includes;..\..\illustratorapi\adm;..\..\illustratorapi\ate;..\..\illustratorapi\illustrator;..\..\illustratorapi\illustrator\actions;..\..\illustratorapi\pica_sp;..\..\illustratorapi\illustrator\legacy;%(AdditionalIncludeDirectories) 116 | _DEBUG;WIN32;_WINDOWS;WIN_ENV;WINNT_ENV;%(PreprocessorDefinitions) 117 | MultiThreadedDebugDLL 118 | 8Bytes 119 | Use 120 | IllustratorSDK.h 121 | $(IntDir)Ai2Canvas.pch 122 | $(IntDir) 123 | $(IntDir) 124 | $(IntDir) 125 | true 126 | Level4 127 | true 128 | ProgramDatabase 129 | CompileAsCpp 130 | pragma.h;%(ForcedIncludeFiles) 131 | false 132 | true 133 | true 134 | false 135 | true 136 | 137 | 138 | _DEBUG;%(PreprocessorDefinitions) 139 | 0x0409 140 | .\Source;..\Source;..\common\win;..\common\includes;..\..\common\win;..\..\common\includes;%(AdditionalIncludeDirectories) 141 | 142 | 143 | ..\output\win\$(Platform)\$(Configuration)\Ai2Canvas$(PlatformArchitecture).aip 144 | true 145 | ..\common\win\PluginMain.def 146 | true 147 | ./Ai2Canvas.pdb 148 | Windows 149 | false 150 | 151 | 152 | ./Ai2Canvas.lib 153 | MachineX86 154 | true 155 | 156 | 157 | 158 | 159 | _DEBUG;%(PreprocessorDefinitions) 160 | true 161 | true 162 | X64 163 | ./TextFileFormatProject.tlb 164 | 165 | 166 | 167 | 168 | Disabled 169 | .\Source;.\Resources;..\common\includes;..\..\illustratorapi\adm;..\..\illustratorapi\ate;..\..\illustratorapi\illustrator;..\..\illustratorapi\illustrator\actions;..\..\illustratorapi\pica_sp;..\..\illustratorapi\illustrator\legacy;%(AdditionalIncludeDirectories) 170 | _DEBUG;_WINDOWS;WIN_ENV;WINNT_ENV;%(PreprocessorDefinitions) 171 | MultiThreadedDebugDLL 172 | 8Bytes 173 | Use 174 | IllustratorSDK.h 175 | $(IntDir)Ai2Canvas.pch 176 | $(IntDir) 177 | $(IntDir) 178 | $(IntDir) 179 | true 180 | Level4 181 | true 182 | ProgramDatabase 183 | CompileAsCpp 184 | pragma.h;%(ForcedIncludeFiles) 185 | false 186 | true 187 | true 188 | false 189 | true 190 | 191 | 192 | _DEBUG;%(PreprocessorDefinitions) 193 | 0x0409 194 | .\Source;..\Source;..\common\win;..\common\includes;..\..\common\win;..\..\common\includes;%(AdditionalIncludeDirectories) 195 | 196 | 197 | ..\output\win\$(Platform)\$(Configuration)\Ai2Canvas$(PlatformArchitecture).aip 198 | true 199 | ..\common\win\PluginMain.def 200 | true 201 | ./Ai2Canvas.pdb 202 | Windows 203 | false 204 | 205 | 206 | ./Ai2Canvas.lib 207 | MachineX64 208 | true 209 | 210 | 211 | python ..\..\tools\pipl\create_pipl.py -input "[{\"name\":\"$(ProjectName)$(PlatformArchitecture)\",\"entry_point\" : \"PluginMain\"}]" 212 | 213 | 214 | 215 | 216 | _DEBUG;%(PreprocessorDefinitions) 217 | true 218 | true 219 | Win32 220 | ./TextFileFormatProject.tlb 221 | 222 | 223 | 224 | 225 | Disabled 226 | .\Source;.\Resources;..\common\includes;..\..\illustratorapi\adm;..\..\illustratorapi\ate;..\..\illustratorapi\illustrator;..\..\illustratorapi\illustrator\actions;..\..\illustratorapi\pica_sp;..\..\illustratorapi\illustrator\legacy;%(AdditionalIncludeDirectories) 227 | NDEBUG;WIN32;_WINDOWS;WIN_ENV;WINNT_ENV;%(PreprocessorDefinitions) 228 | MultiThreaded 229 | 8Bytes 230 | Use 231 | IllustratorSDK.h 232 | $(IntDir)Ai2Canvas.pch 233 | $(IntDir) 234 | $(IntDir) 235 | $(IntDir) 236 | true 237 | Level4 238 | true 239 | ProgramDatabase 240 | CompileAsCpp 241 | pragma.h;%(ForcedIncludeFiles) 242 | false 243 | true 244 | true 245 | false 246 | true 247 | 248 | 249 | NDEBUG;%(PreprocessorDefinitions) 250 | 0x0409 251 | .\Source;..\Source;..\common\win;..\common\includes;..\..\common\win;..\..\common\includes;%(AdditionalIncludeDirectories) 252 | 253 | 254 | ..\output\win\$(Platform)\$(Configuration)\Ai2Canvas$(PlatformArchitecture).aip 255 | true 256 | ..\common\win\PluginMain.def 257 | false 258 | ./Ai2Canvas.pdb 259 | Windows 260 | false 261 | 262 | 263 | ./Ai2Canvas.lib 264 | MachineX86 265 | true 266 | 267 | 268 | 269 | 270 | _DEBUG;%(PreprocessorDefinitions) 271 | true 272 | true 273 | X64 274 | ./TextFileFormatProject.tlb 275 | 276 | 277 | 278 | 279 | Disabled 280 | .\Source;.\Resources;..\common\includes;..\..\illustratorapi\adm;..\..\illustratorapi\ate;..\..\illustratorapi\illustrator;..\..\illustratorapi\illustrator\actions;..\..\illustratorapi\pica_sp;..\..\illustratorapi\illustrator\legacy;%(AdditionalIncludeDirectories) 281 | NDEBUG;_WINDOWS;WIN_ENV;WINNT_ENV;%(PreprocessorDefinitions) 282 | MultiThreadedDLL 283 | 8Bytes 284 | NotUsing 285 | IllustratorSDK.h 286 | $(IntDir)Ai2Canvas.pch 287 | $(IntDir) 288 | $(IntDir) 289 | $(IntDir) 290 | true 291 | Level4 292 | true 293 | ProgramDatabase 294 | CompileAsCpp 295 | pragma.h;%(ForcedIncludeFiles) 296 | false 297 | true 298 | true 299 | false 300 | true 301 | /std:c++14 /Zc:sizedDealloc- %(AdditionalOptions) 302 | 303 | 304 | NDEBUG;%(PreprocessorDefinitions) 305 | 0x0409 306 | .\Source;..\Source;..\common\win;..\common\includes;..\..\common\win;..\..\common\includes;%(AdditionalIncludeDirectories) 307 | 308 | 309 | ..\output\win\$(Platform)\$(Configuration)\Ai2Canvas$(PlatformArchitecture).aip 310 | true 311 | ..\common\win\PluginMain.def 312 | false 313 | ./Ai2Canvas.pdb 314 | Windows 315 | false 316 | 317 | 318 | ./Ai2Canvas.lib 319 | MachineX64 320 | true 321 | 322 | 323 | python ..\..\tools\pipl\create_pipl.py -input "[{\"name\":\"$(ProjectName)$(PlatformArchitecture)\",\"entry_point\" : \"PluginMain\"}]" 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | Create 384 | Create 385 | Create 386 | Create 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | -------------------------------------------------------------------------------- /Ai2Canvas.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Ai2Canvas.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Ai2Canvas.xcodeproj/xcshareddata/xcschemes/Ai2Canvas.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 57 | 58 | 59 | 60 | 62 | 63 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | $(PROJECTNAME) 9 | CFBundleExecutable 10 | $(PROJECTNAME) 11 | CFBundleGetInfoHTML 12 | Ai->Canvas Export Plug-In $(MARKETING_VERSION), Copyright 2010-2022 Mike Swanson. All rights reserved. 13 | CFBundleGetInfoString 14 | Ai->Canvas Export Plug-In $(MARKETING_VERSION), Copyright 2010-2022 Mike Swanson. All rights reserved. 15 | CFBundleIdentifier 16 | $(PRODUCT_BUNDLE_IDENTIFIER) 17 | CFBundleInfoDictionaryVersion 18 | 6.0 19 | CFBundleName 20 | $(PROJECTNAME) 21 | CFBundlePackageType 22 | ARPI 23 | CFBundleShortVersionString 24 | $(MARKETING_VERSION) 25 | CFBundleSignature 26 | ART5 27 | CFBundleVersion 28 | $(CURRENT_PROJECT_VERSION) 29 | CSResourcesFileMapped 30 | 31 | LSRequiresCarbon 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2010-2014 Mike Swanson (http://blog.mikeswanson.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ai2Canvas # 2 | 3 | By [Mike Swanson](http://blog.mikeswanson.com/) 4 | 5 | The Ai->Canvas plug-in enables Adobe Illustrator to export vector and bitmap artwork directly to an HTML5 canvas element using JavaScript drawing commands. Animation can be added to control rotation, scaling, opacity, and motion along a path. Then, events can be used to trigger other animations. Finally, the exported HTML and JavaScript can be extended and used in applications running on the latest versions of Internet Explorer, Firefox, Chrome, Safari, and Opera. 6 | 7 | This brief video (while a bit dated) provides an overview of the plug-in’s functionality. 8 | 9 | [![Ai2Canvas Overview](http://img.youtube.com/vi/L1W9AyK2MPc/0.jpg)](http://www.youtube.com/watch?v=L1W9AyK2MPc) 10 | 11 | ## Requirements ## 12 | 13 | This repository includes both a Visual Studio 2019 solution for PC and a Xcode 13.0 project for Mac. It also requires the Adobe Illustrator CC 2022 SDK. 14 | 15 | ## Getting Started ## 16 | 17 | Because the project depends on the Illustrator SDK and references many files using relative paths, it is important to place the project in the correct location. 18 | 19 | 1. Download and extract the Adobe Illustrator CC 2022 SDK for PC or Mac from the [Adobe Developer Console](https://console.adobe.io/). 20 | 21 | 2. From the _Adobe Illustrator CC 2022 SDK/samplecode_ folder: 22 | 23 | git clone https://github.com/mikeswanson/Ai2Canvas.git 24 | 25 | 3. The _Adobe Illustrator 2022 SDK/tools/pipl/pipl_gen/pipl_gen.py_ file is based on Python 2.7 which Apple removed starting with macOS Monterey (12.3). I've updated the build scripts to use Python 3, so you'll need to manually "upgrade" this script. I'm probably not allowed to host the edited file, but the good news is that there are only a handful of lines to change. 26 | 27 | - Replace all of the `is` and `is not` conditionals with `==` and `!=`. 28 | - When `key` or `pipl_dict[key]` values are written to the file, `.encode('utf-8')` them first. 29 | 30 | 4. You can now open and build the Visual Studio solution or the Xcode project. Output can be found in the _Adobe Illustrator CC 2022 SDK/samplecode/output_ folder. 31 | 32 | If you decide to move the project, you will need to update the many relevant paths. As a historical note, Ai->Canvas started its life based on an older version of Adobe's _TextFileFormat_ sample, and it was easiest to create the new project in a parallel folder to keep the relative references intact. 33 | 34 | ## Documentation ## 35 | 36 | For more detail about how the plug-in works along with a full tutorial and extended documentation, visit the [Ai->Canvas Plug-In for Adobe Illustrator](http://blog.mikeswanson.com/ai2canvas) project page on my blog. 37 | -------------------------------------------------------------------------------- /Resources/Ai2Canvas.r: -------------------------------------------------------------------------------- 1 | //======================================================================================== 2 | // 3 | // $File: //ai/cs6/devtech/sdk/public/samplecode/TextFileFormat/Resources/TextFileFormat.r $ 4 | // 5 | // $Revision: #2 $ 6 | // 7 | // Copyright 1987 Adobe Systems Incorporated. All rights reserved. 8 | // 9 | // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance 10 | // with the terms of the Adobe license agreement accompanying it. If you have received 11 | // this file from a source other than Adobe, then your use, modification, or 12 | // distribution of it requires the prior written permission of Adobe. 13 | // 14 | //======================================================================================== 15 | 16 | #define PIPL_PLUGIN_NAME "Ai2Canvas" 17 | #include "Plugin.r" 18 | -------------------------------------------------------------------------------- /Resources/Ai2Canvas.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include "afxres.h" 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (United States) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 19 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 20 | #pragma code_page(1252) 21 | 22 | ///////////////////////////////////////////////////////////////////////////// 23 | // 24 | // Version 25 | // 26 | 27 | 1 VERSIONINFO 28 | FILEVERSION 16,0,0,0 29 | PRODUCTVERSION 16,0,0,0 30 | FILEFLAGSMASK 0x3fL 31 | #ifdef _DEBUG 32 | FILEFLAGS 0x1L 33 | #else 34 | FILEFLAGS 0x0L 35 | #endif 36 | FILEOS 0x4L 37 | FILETYPE 0x2L 38 | FILESUBTYPE 0x0L 39 | BEGIN 40 | BLOCK "StringFileInfo" 41 | BEGIN 42 | BLOCK "040904e4" 43 | BEGIN 44 | VALUE "CompanyName", "Mike Swanson" 45 | VALUE "Copyright", "Copyright 2010-2022 Mike Swanson. All rights reserved." 46 | VALUE "FileDescription", "Ai->Canvas Export Plug-In" 47 | VALUE "FileVersion", "16.0" 48 | VALUE "InternalName", "Ai->Canvas" 49 | VALUE "LegalCopyright", "Copyright 2010-2022 Mike Swanson. All rights reserved." 50 | VALUE "OriginalFilename", "Ai2Canvas.aip" 51 | VALUE "ProductName", "Ai->Canvas" 52 | VALUE "ProductVersion", "1.8" 53 | END 54 | END 55 | BLOCK "VarFileInfo" 56 | BEGIN 57 | VALUE "Translation", 0x409, 1252 58 | END 59 | END 60 | 61 | 62 | ///////////////////////////////////////////////////////////////////////////// 63 | // 64 | // PIPL 65 | // 66 | 67 | plugin pipl "plugin.pipl" 68 | 69 | #ifdef APSTUDIO_INVOKED 70 | ///////////////////////////////////////////////////////////////////////////// 71 | // 72 | // TEXTINCLUDE 73 | // 74 | 75 | 1 TEXTINCLUDE 76 | BEGIN 77 | "resource.h\0" 78 | END 79 | 80 | 2 TEXTINCLUDE 81 | BEGIN 82 | "#include ""afxres.h""\r\n" 83 | "\0" 84 | END 85 | 86 | 3 TEXTINCLUDE 87 | BEGIN 88 | "\r\n" 89 | "\0" 90 | END 91 | 92 | #endif // APSTUDIO_INVOKED 93 | 94 | #endif // English (United States) resources 95 | ///////////////////////////////////////////////////////////////////////////// 96 | 97 | 98 | 99 | #ifndef APSTUDIO_INVOKED 100 | ///////////////////////////////////////////////////////////////////////////// 101 | // 102 | // Generated from the TEXTINCLUDE 3 resource. 103 | // 104 | 105 | 106 | ///////////////////////////////////////////////////////////////////////////// 107 | #endif // not APSTUDIO_INVOKED 108 | 109 | -------------------------------------------------------------------------------- /Resources/resource.h: -------------------------------------------------------------------------------- 1 | // resource.h 2 | // 3 | // Copyright (c) 2010-2020 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifdef APSTUDIO_INVOKED 24 | #ifndef APSTUDIO_READONLY_SYMBOLS 25 | #define _APS_NEXT_RESOURCE_VALUE 107 26 | #define _APS_NEXT_COMMAND_VALUE 40001 27 | #define _APS_NEXT_CONTROL_VALUE 1000 28 | #define _APS_NEXT_SYMED_VALUE 101 29 | #endif 30 | #endif 31 | -------------------------------------------------------------------------------- /Scripting/CanvasExportScript.jsx: -------------------------------------------------------------------------------- 1 | result = app.sendScriptMessage ( 2 | "Ai2Canvas", 3 | "Export", 4 | 'c:\\temp\\output.html' 5 | ); 6 | alert(result); -------------------------------------------------------------------------------- /Source/Ai2CanvasID.h: -------------------------------------------------------------------------------- 1 | // Ai2CanvasID.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef __AI2CANVASID_H__ 24 | #define __AI2CANVASID_H__ 25 | 26 | #define kAi2CanvasPluginName "Ai2Canvas" 27 | 28 | #endif // End Ai2CanvasID.h 29 | -------------------------------------------------------------------------------- /Source/Ai2CanvasPlugin.cpp: -------------------------------------------------------------------------------- 1 | // Ai2CanvasPlugin.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "AIScriptMessage.h" 25 | #include "Ai2CanvasPlugin.h" 26 | 27 | // CanvasExport stuff 28 | #include "Utility.h" 29 | #include "Document.h" 30 | #include "Image.h" 31 | #include "State.h" 32 | #include "Canvas.h" 33 | 34 | #ifdef MAC_ENV 35 | #include 36 | #endif 37 | 38 | #ifdef WIN_ENV 39 | #include "shellapi.h" 40 | #endif 41 | 42 | #define kSelectorAIScriptExport "Export" 43 | 44 | using namespace CanvasExport; 45 | 46 | namespace CanvasExport 47 | { 48 | // Globals 49 | ofstream outFile; 50 | bool debug; 51 | } 52 | 53 | /* 54 | */ 55 | Plugin* AllocatePlugin(SPPluginRef pluginRef) 56 | { 57 | return new Ai2CanvasPlugin(pluginRef); 58 | } 59 | 60 | /* 61 | */ 62 | void FixupReload(Plugin* plugin) 63 | { 64 | Ai2CanvasPlugin::FixupVTable((Ai2CanvasPlugin*) plugin); 65 | } 66 | 67 | /* 68 | */ 69 | Ai2CanvasPlugin::Ai2CanvasPlugin(SPPluginRef pluginRef) 70 | : Plugin(pluginRef) 71 | { 72 | strncpy(fPluginName, kAi2CanvasPluginName, kMaxStringLength); 73 | } 74 | 75 | /* 76 | */ 77 | ASErr Ai2CanvasPlugin::Message(char* caller, char* selector, void *message) 78 | { 79 | ASErr error = kNoErr; 80 | 81 | // Is this command being sent from an Illustrator script? 82 | if (strcmp(caller, kCallerAIScriptMessage) == 0) 83 | { 84 | bool isRecognizedCommand = false; 85 | 86 | AIScriptMessage* msg = (AIScriptMessage*)message; 87 | ai::UnicodeString outParam(""); 88 | 89 | // Export command? 90 | if (strcmp(selector, kSelectorAIScriptExport) == 0) 91 | { 92 | isRecognizedCommand = true; 93 | } 94 | // Unrecognized command 95 | else 96 | { 97 | isRecognizedCommand = false; 98 | 99 | outParam.append(ai::UnicodeString("Unrecognized command: '")); 100 | outParam.append(ai::UnicodeString(selector)); 101 | outParam.append(ai::UnicodeString("'")); 102 | outParam.append(ai::UnicodeString(" (only valid command is '")); 103 | outParam.append(ai::UnicodeString(kSelectorAIScriptExport)); 104 | outParam.append(ai::UnicodeString("')")); 105 | } 106 | 107 | if (isRecognizedCommand) 108 | { 109 | if (msg->inParam.empty()) 110 | { 111 | outParam.append(ai::UnicodeString("No output path provided")); 112 | } 113 | else 114 | { 115 | char pathName[300]; 116 | msg->inParam.as_Roman(pathName, 300); 117 | 118 | error = WriteText(pathName, false); 119 | if (error == kNoErr) 120 | { 121 | outParam.append(ai::UnicodeString("Exported to: '")); 122 | } 123 | else 124 | { 125 | outParam.append(ai::UnicodeString("Error exporting to: '")); 126 | } 127 | 128 | outParam.append(msg->inParam); 129 | outParam.append(ai::UnicodeString("'")); 130 | } 131 | } 132 | 133 | // Return the output message as a parameter 134 | msg->outParam = outParam; 135 | } 136 | else 137 | { 138 | try { 139 | error = Plugin::Message(caller, selector, message); 140 | } 141 | catch (ai::Error& ex) { 142 | error = ex; 143 | } 144 | catch (...) { 145 | error = kCantHappenErr; 146 | } 147 | if (error) { 148 | if (error == kUnhandledMsgErr) { 149 | // Defined by Plugin.hpp and used in Plugin::Message - ignore. 150 | error = kNoErr; 151 | } 152 | else { 153 | Plugin::ReportError(error, caller, selector, message); 154 | } 155 | } 156 | } 157 | 158 | return error; 159 | } 160 | 161 | 162 | /* 163 | */ 164 | ASErr Ai2CanvasPlugin::StartupPlugin(SPInterfaceMessage* message) 165 | { 166 | ASErr error = kNoErr; 167 | error = Plugin::StartupPlugin(message); 168 | if (error) { return error; } 169 | error = this->AddMenus(message); 170 | if (error) { return error; } 171 | error = this->AddFileFormats(message); 172 | 173 | return error; 174 | } 175 | 176 | ASErr Ai2CanvasPlugin::GoMenuItem(AIMenuMessage* message) 177 | { 178 | ASErr error = kNoErr; 179 | if (message->menuItem == this->fAboutPluginMenu) { 180 | // Pop this plug-in's about box. 181 | SDKAboutPluginsHelper aboutPluginsHelper; 182 | 183 | #ifdef MAC_ENV 184 | aboutPluginsHelper.PopAboutBox(message, "Ai->Canvas Export Plug-In 1.8 (Mac)", "Copyright 2010-2022 Mike Swanson\nAll rights reserved\nhttp://blog.mikeswanson.com/"); 185 | #endif 186 | #ifdef WIN_ENV 187 | #ifdef _WIN64 188 | aboutPluginsHelper.PopAboutBox(message, "Ai->Canvas Export Plug-In 1.8 (PC/64)", "Copyright 2010-2022 Mike Swanson\nAll rights reserved\nhttp://blog.mikeswanson.com/"); 189 | #else 190 | aboutPluginsHelper.PopAboutBox(message, "Ai->Canvas Export Plug-In 1.8 (PC/32)", "Copyright 2010-2022 Mike Swanson\nAll rights reserved\nhttp://blog.mikeswanson.com/"); 191 | #endif 192 | #endif 193 | } 194 | return error; 195 | } 196 | 197 | 198 | ASErr Ai2CanvasPlugin::AddMenus(SPInterfaceMessage* message) { 199 | ASErr error = kNoErr; 200 | // Add a menu item to the About SDK Plug-ins menu group. 201 | SDKAboutPluginsHelper aboutPluginsHelper; 202 | error = aboutPluginsHelper.AddAboutPluginsMenuItem(message, 203 | "AboutMikeSwansonPluginsGroupName", 204 | ai::UnicodeString("About Mike Swanson Plug-Ins"), 205 | "Ai->Canvas...", 206 | &this->fAboutPluginMenu); 207 | return error; 208 | } 209 | 210 | ASErr Ai2CanvasPlugin::AddFileFormats(SPInterfaceMessage* message) 211 | { 212 | ASErr error = kNoErr; 213 | 214 | PlatformAddFileFormatData affd; 215 | char pstrCanvas[kMaxStringLength] = ""; 216 | 217 | affd.title = ai::UnicodeString::FromRoman(pstrCanvas); 218 | affd.titleOrder = 0; 219 | affd.extension = ai::UnicodeString::FromRoman("html"); 220 | 221 | error = sAIFileFormat->AddFileFormat( message->d.self, "", 222 | &affd, kFileFormatExport, 223 | &this->fFileFormatCanvas, kNoExtendedOptions ); 224 | return error; 225 | } 226 | 227 | ASErr Ai2CanvasPlugin::GoFileFormat(AIFileFormatMessage* message) 228 | { 229 | ASErr error = kNoErr; 230 | char pathName[300]; 231 | 232 | message->GetFilePath().GetFullPath().as_Roman( pathName, 300); 233 | 234 | if ( message->option & kFileFormatExport ) 235 | { 236 | // Export our HTM canvas file 237 | error = WriteText(pathName, true); 238 | } 239 | 240 | return error; 241 | } 242 | 243 | ASErr Ai2CanvasPlugin::WriteText(const char* pathName, AIBoolean openFile) 244 | { 245 | ASErr error = kNoErr; 246 | 247 | #ifdef MAC_ENV 248 | // Determine if shift key is being held down (can't distinguish between left/right shift keys using this method on OS X) 249 | // bool debugActivated = ((GetCurrentKeyModifiers() & (1 << shiftKeyBit)) != 0); 250 | 251 | bool debugActivated = (CGEventSourceFlagsState(kCGEventSourceStateHIDSystemState) & kCGEventFlagMaskShift); 252 | #endif 253 | #ifdef WIN_ENV 254 | // Determine if the left shift key is being held down (to indicate previewing HTML file after export) 255 | bool debugActivated = ((GetKeyState(VK_LSHIFT) &0x1000) != 0); 256 | #endif 257 | 258 | // Create file 259 | std::string file = std::string(pathName); 260 | if (OpenFile(file)) 261 | { 262 | // Set debug mode 263 | //CanvasExport::debug = (openFile != 0); 264 | CanvasExport::debug = debugActivated; 265 | 266 | // Create a new document 267 | Document* document = new Document(file); 268 | 269 | // Render the document 270 | document->Render(); 271 | 272 | // Close the file 273 | CloseFile(); 274 | 275 | // Delete document 276 | delete document; 277 | } 278 | 279 | #ifdef MAC_ENV 280 | // Create file URI 281 | ai::UnicodeString usPath(file); 282 | ai::FilePath aiFilePath(usPath); 283 | std::string uri = aiFilePath.GetAsURL(false).as_Platform(); 284 | 285 | // Launch the file 286 | if (openFile) 287 | { 288 | std::string command = "open " + uri; 289 | system(command.c_str()); 290 | } 291 | #endif 292 | #ifdef WIN_ENV 293 | // Launch the file 294 | if (openFile) 295 | { 296 | ShellExecute(NULL, "open", pathName, NULL, NULL, SW_SHOWNORMAL); 297 | } 298 | #endif 299 | 300 | return error; 301 | } 302 | 303 | // End Ai2CanvasPlugin.cpp 304 | -------------------------------------------------------------------------------- /Source/Ai2CanvasPlugin.h: -------------------------------------------------------------------------------- 1 | // Ai2CanvasPlugin.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef __AI2CANVASPLUGIN_H__ 24 | #define __AI2CANVASPLUGIN_H__ 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Plugin.hpp" 28 | #include "Ai2CanvasID.h" 29 | #include "Ai2CanvasSuites.h" 30 | #include "SDKAboutPluginsHelper.h" 31 | 32 | #define kMaxStringLength 256 33 | 34 | /** Creates a new Ai2CanvasPlugin. 35 | @param pluginRef IN unique reference to this plugin. 36 | @return pointer to new Ai2CanvasPlugin. 37 | */ 38 | Plugin* AllocatePlugin(SPPluginRef pluginRef); 39 | 40 | /** Reloads the Ai2CanvasPlugin class state when the plugin is 41 | reloaded by the application. 42 | @param plugin IN pointer to plugin being reloaded. 43 | */ 44 | void FixupReload(Plugin* plugin); 45 | 46 | /** Provides a plugin which demonstrates adding new file formats to open and save to. 47 | */ 48 | class Ai2CanvasPlugin : public Plugin 49 | { 50 | public: 51 | /** Constructor. 52 | @param pluginRef IN reference to this plugin. 53 | */ 54 | Ai2CanvasPlugin(SPPluginRef pluginRef); 55 | 56 | /** Destructor. 57 | */ 58 | virtual ~Ai2CanvasPlugin(){} 59 | 60 | /** Restores state of Ai2CanvasPlugin during reload. 61 | */ 62 | FIXUP_VTABLE_EX(Ai2CanvasPlugin, Plugin); 63 | 64 | protected: 65 | /** Calls Plugin::Message and handles any errors returned. 66 | @param caller IN sender of the message. 67 | @param selector IN nature of the message. 68 | @param message IN pointer to plugin and call information. 69 | @return kNoErr on success, other ASErr otherwise. 70 | */ 71 | virtual ASErr Message(char* caller, char* selector, void *message); 72 | 73 | /** Calls Plugin::Startup and initialisation functions, such as 74 | AddMenus and AddNotifiers. 75 | @param message IN pointer to plugin and call information. 76 | @return kNoErr on success, other ASErr otherwise. 77 | */ 78 | virtual ASErr StartupPlugin(SPInterfaceMessage* message); 79 | 80 | /** Performs actions required for menu item selected. 81 | @param message IN pointer to plugin and call information. 82 | @return kNoErr on success, other ASErr otherwise. 83 | */ 84 | virtual ASErr GoMenuItem(AIMenuMessage* message); 85 | 86 | /** Performs actions required for file format selected. 87 | @param message IN pointer to plugin and call information. 88 | @return kNoErr on success, other ASErr otherwise. 89 | */ 90 | virtual ASErr GoFileFormat(AIFileFormatMessage* message); 91 | 92 | private: 93 | /** File format handle for Selected Text as Text. 94 | */ 95 | AIFileFormatHandle fFileFormatCanvas; 96 | 97 | /** Menu item handle for this plugins About menu. 98 | */ 99 | AIMenuItemHandle fAboutPluginMenu; 100 | 101 | /** Adds the menu items for this plugin to the application UI. 102 | @param message IN pointer to plugin and call information. 103 | @return kNoErr on success, other ASErr otherwise. 104 | */ 105 | ASErr AddMenus(SPInterfaceMessage* message); 106 | 107 | /** Adds the file formats for this plugin to the application. 108 | @param message IN pointer to plugin and call information. 109 | @return kNoErr on success, other ASErr otherwise. 110 | */ 111 | ASErr AddFileFormats(SPInterfaceMessage* message); 112 | 113 | /** Writes the text to the file. 114 | @param pathName IN path to file. 115 | @param openFile IN true to open exported file. 116 | @return kNoErr on success, other ASErr otherwise. 117 | */ 118 | ASErr WriteText(const char* pathName, AIBoolean openFile); 119 | }; 120 | #endif // End Ai2CanvasPlugin.h 121 | -------------------------------------------------------------------------------- /Source/Ai2CanvasSuites.cpp: -------------------------------------------------------------------------------- 1 | // Ai2CanvasSuites.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "Ai2CanvasSuites.h" 25 | 26 | extern "C" 27 | { 28 | AIUnicodeStringSuite* sAIUnicodeString = nullptr; 29 | SPBlocksSuite* sSPBlocks = nullptr; 30 | AIFileFormatSuite* sAIFileFormat = nullptr; 31 | AIDocumentSuite* sAIDocument = nullptr; 32 | AITextFrameSuite* sAITextFrame = nullptr; 33 | AIArtSuite* sAIArt = nullptr; 34 | AIPathSuite* sAIPath = nullptr; 35 | AIMatchingArtSuite* sAIMatchingArt = nullptr; 36 | AIMdMemorySuite* sAIMdMemory = nullptr; 37 | EXTERN_TEXT_SUITES 38 | 39 | // Added for Ai2Canvas functionality 40 | AIPathStyleSuite *sAIPathStyle = nullptr; 41 | AIHardSoftSuite *sAIHardSoft = nullptr; 42 | AIRealMathSuite *sAIRealMath = nullptr; 43 | AIGradientSuite *sAIGradient = nullptr; 44 | AIMaskSuite *sAIMask = nullptr; 45 | AIPluginGroupSuite *sAIPluginGroup = nullptr; 46 | AICustomColorSuite *sAICustomColor = nullptr; 47 | AIColorConversionSuite *sAIColorConversion = nullptr; 48 | AIBlendStyleSuite *sAIBlendStyle = nullptr; 49 | AILayerSuite *sAILayer = nullptr; 50 | AIATEPaintSuite *sATEPaint = nullptr; 51 | AIFontSuite *sAIFont = nullptr; 52 | AIATETextUtilSuite *sATETextUtil = nullptr; 53 | AIDataFilterSuite *sAIDataFilter = nullptr; 54 | AISymbolSuite *sAISymbol = nullptr; 55 | AIPatternSuite *sAIPattern = nullptr; 56 | AIPlacedSuite *sAIPlaced = nullptr; 57 | AIRasterSuite *sAIRaster = nullptr; 58 | AIImageOptSuite *sAIImageOpt = nullptr; 59 | AIArtStyleSuite *sAIArtStyle = nullptr; 60 | AIArtStyleParserSuite *sAIArtStyleParser = nullptr; 61 | AILiveEffectSuite *sAILiveEffect = nullptr; 62 | AIDictionarySuite *sAIDictionary = nullptr; 63 | AIDictionaryIteratorSuite *sAIDictionaryIterator = nullptr; 64 | AIEntrySuite *sAIEntry = nullptr; 65 | AIRealBezierSuite *sAIRealBezier = nullptr; 66 | }; 67 | 68 | ImportSuite gImportSuites[] = 69 | { 70 | kAIUnicodeStringSuite, kAIUnicodeStringSuiteVersion, &sAIUnicodeString, 71 | kSPBlocksSuite, kSPBlocksSuiteVersion, &sSPBlocks, 72 | kAIFileFormatSuite, kAIFileFormatVersion, &sAIFileFormat, 73 | kAIDocumentSuite, kAIDocumentVersion, &sAIDocument, 74 | kAITextFrameSuite, kAITextFrameVersion, &sAITextFrame, 75 | kAIArtSuite, kAIArtSuiteVersion, &sAIArt, 76 | kAIPathSuite, kAIPathVersion, &sAIPath, 77 | kAIMatchingArtSuite, kAIMatchingArtVersion, &sAIMatchingArt, 78 | kAIMdMemorySuite, kAIMdMemorySuiteVersion, &sAIMdMemory, 79 | 80 | // Added for Ai2Canvas functionality 81 | kAIPathStyleSuite, kAIPathStyleVersion, &sAIPathStyle, 82 | kAIHardSoftSuite, kAIHardSoftVersion, &sAIHardSoft, 83 | kAIRealMathSuite, kAIRealMathVersion, &sAIRealMath, 84 | kAIGradientSuite, kAIGradientVersion, &sAIGradient, 85 | kAIMaskSuite, kAIMaskVersion, &sAIMask, 86 | kAIPluginGroupSuite, kAIPluginGroupVersion, &sAIPluginGroup, 87 | kAICustomColorSuite, kAICustomColorVersion, &sAICustomColor, 88 | kAIColorConversionSuite, kAIColorConversionVersion, &sAIColorConversion, 89 | kAIBlendStyleSuite, kAIBlendStyleVersion, &sAIBlendStyle, 90 | kAILayerSuite, kAILayerVersion, &sAILayer, 91 | kAIATEPaintSuite, kAIATEPaintSuiteVersion, &sATEPaint, 92 | kAIFontSuite, kAIFontSuiteVersion, &sAIFont, 93 | kAIATETextUtilSuite, kAIATETextUtilSuiteVersion, &sATETextUtil, 94 | kAIDataFilterSuite, kAIDataFilterSuiteVersion, &sAIDataFilter, 95 | kAISymbolSuite, kAISymbolSuiteVersion, &sAISymbol, 96 | kAIPatternSuite, kAIPatternSuiteVersion, &sAIPattern, 97 | kAIPlacedSuite, kAIPlacedSuiteVersion, &sAIPlaced, 98 | kAIRasterSuite, kAIRasterSuiteVersion, &sAIRaster, 99 | kAIArtStyleSuite, kAIArtStyleSuiteVersion, &sAIArtStyle, 100 | kAIArtStyleParserSuite, kAIArtStyleParserSuiteVersion, &sAIArtStyleParser, 101 | kAILiveEffectSuite, kAILiveEffectSuiteVersion, &sAILiveEffect, 102 | kAIDictionarySuite, kAIDictionarySuiteVersion, &sAIDictionary, 103 | kAIDictionaryIteratorSuite, kAIDictionaryIteratorSuiteVersion, &sAIDictionaryIterator, 104 | kAIEntrySuite, kAIEntrySuiteVersion, &sAIEntry, 105 | kAIImageOptSuite, kAIImageOptSuiteVersion, &sAIImageOpt, 106 | kAIRealBezierSuite, kAIRealBezierSuiteVersion, &sAIRealBezier, 107 | 108 | IMPORT_TEXT_SUITES 109 | nullptr, 0, nullptr 110 | }; 111 | 112 | 113 | // End Ai2CanvasSuites.cpp 114 | -------------------------------------------------------------------------------- /Source/Ai2CanvasSuites.h: -------------------------------------------------------------------------------- 1 | // Ai2CanvasSuites.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef __AI2CANVASSUITES_H__ 24 | #define __AI2CANVASSUITES_H__ 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Suites.hpp" 28 | #include "ATETextSuitesImportHelper.h" 29 | 30 | // Added for Ai2Canvas functionality 31 | #include "AIColorConversion.h" 32 | #include "AIATEPaint.h" 33 | #include "AIATETextUtil.h" 34 | #include "AIImageOptimization.h" 35 | #include "AISymbol.h" 36 | #include "AIArtStyleParser.h" 37 | #include "AIPattern.h" 38 | #include "AIPathStyle.h" 39 | #include "AIGradient.h" 40 | 41 | extern "C" AIUnicodeStringSuite* sAIUnicodeString; 42 | extern "C" SPBlocksSuite* sSPBlocks; 43 | extern "C" AIFileFormatSuite* sAIFileFormat; 44 | extern "C" AIDocumentSuite* sAIDocument; 45 | extern "C" AITextFrameSuite* sAITextFrame; 46 | extern "C" AIArtSuite* sAIArt; 47 | extern "C" AIPathSuite* sAIPath; 48 | extern "C" AIMatchingArtSuite* sAIMatchingArt; 49 | extern "C" AIMdMemorySuite* sAIMdMemory; 50 | 51 | // Added for Ai2Canvas functionality 52 | extern "C" AIATEPaintSuite *sATEPaint; 53 | extern "C" AIFontSuite *sAIFont; 54 | extern "C" AIATETextUtilSuite *sATETextUtil; 55 | extern "C" AIDataFilterSuite *sAIDataFilter; 56 | extern "C" AISymbolSuite *sAISymbol; 57 | extern "C" AIPatternSuite *sAIPattern; 58 | extern "C" AIPlacedSuite *sAIPlaced; 59 | extern "C" AIRasterSuite *sAIRaster; 60 | extern "C" AIImageOptSuite *sAIImageOpt; 61 | extern "C" AIArtStyleSuite *sAIArtStyle; 62 | extern "C" AIArtStyleParserSuite *sAIArtStyleParser; 63 | extern "C" AILiveEffectSuite *sAILiveEffect; 64 | extern "C" AIDictionarySuite *sAIDictionary; 65 | extern "C" AIDictionaryIteratorSuite *sAIDictionaryIterator; 66 | extern "C" AIEntrySuite *sAIEntry; 67 | extern "C" AIPathStyleSuite *sAIPathStyle; 68 | extern "C" AIHardSoftSuite *sAIHardSoft; 69 | extern "C" AIRealMathSuite *sAIRealMath; 70 | extern "C" AIGradientSuite *sAIGradient; 71 | extern "C" AIMaskSuite *sAIMask; 72 | extern "C" AIPluginGroupSuite *sAIPluginGroup; 73 | extern "C" AICustomColorSuite *sAICustomColor; 74 | extern "C" AIColorConversionSuite *sAIColorConversion; 75 | extern "C" AIBlendStyleSuite *sAIBlendStyle; 76 | extern "C" AILayerSuite *sAILayer; 77 | extern "C" AIRealBezierSuite *sAIRealBezier; 78 | 79 | #endif // End Ai2CanvasSuites.h 80 | -------------------------------------------------------------------------------- /Source/AnimationClock.cpp: -------------------------------------------------------------------------------- 1 | // AnimationClock.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "AnimationClock.h" 25 | 26 | using namespace CanvasExport; 27 | 28 | AnimationClock::AnimationClock() 29 | { 30 | // Initialize AnimationClock 31 | this->name = "animationClock"; 32 | this->duration = 5.0f; 33 | this->delay = 0.0f; 34 | this->direction = AnimationClock::kNone; 35 | this->reverses = false; 36 | this->iterations = 0; 37 | this->timingFunction = "linear"; 38 | this->rangeExpression = ""; 39 | this->multiplier = 1.0f; 40 | this->offset = 0.0f; 41 | } 42 | 43 | AnimationClock::~AnimationClock() 44 | { 45 | // Clear triggers 46 | for (unsigned int i = 0; i < triggers.size(); i++) 47 | { 48 | // Remove instance 49 | delete triggers[i]; 50 | } 51 | } 52 | 53 | // Output JavaScript to create a clock with the given name 54 | void AnimationClock::JSClockInit(const std::string& objectName) 55 | { 56 | // Only initialize if we have animation 57 | if (direction != kNone) 58 | { 59 | outFile << "\n " << objectName << "." << name << " = new clock(" << 60 | setiosflags(ios::fixed) << setprecision(2) << duration << ", " << 61 | delay << ", " << 62 | direction << ", " << 63 | (reverses ? "true" : "false") << ", " << 64 | iterations << ", " << 65 | timingFunction << ", " << 66 | rangeExpression << ", " << 67 | multiplier << ", " << 68 | setprecision(4) << // Increase precision to accomodate Firefox 3.x scaling issue 69 | offset << 70 | ");"; 71 | 72 | if (debug) 73 | { 74 | // Debug animation clock 75 | outFile << "\n " << objectName << "." << name << ".timeProvider = debug; // Debug animation clock (comment out for normal animation)"; 76 | } 77 | } 78 | } 79 | 80 | void AnimationClock::JSClockTriggerInit(const std::string& objectName) 81 | { 82 | // Only initialize if we have animation 83 | if (direction != kNone) 84 | { 85 | // Do we have any triggers? 86 | if (triggers.size() > 0) 87 | { 88 | // Loop through triggers 89 | // animations[0].pathClock.finished.subscribe(function() { animations[0].pathClock.reset(); }); 90 | for (unsigned int i = 0; i < triggers.size(); i++) 91 | { 92 | triggers[i]->JSTriggerInit(objectName, name); 93 | } 94 | } 95 | } 96 | } 97 | 98 | // Outputs correct JavaScript to start a clock immediately 99 | void AnimationClock::JSClockStart(const std::string& objectName) 100 | { 101 | // Only start if we have animation 102 | if (direction != kNone) 103 | { 104 | // And only if we don't have another valid start trigger 105 | if (!HasValidStartTrigger()) 106 | { 107 | outFile << "\n " << objectName << "." << name << ".start();"; 108 | } 109 | } 110 | } 111 | 112 | // Output JavaScript to tick a clock 113 | void AnimationClock::JSClockTick(const std::string& objectName) 114 | { 115 | // Only tick if we have animation 116 | if (direction != kNone) 117 | { 118 | // Output tick 119 | outFile << "\n " << objectName << "." << name << ".update();"; 120 | } 121 | } 122 | 123 | // Does this clock have any valid triggers? 124 | bool AnimationClock::HasValidTriggers() 125 | { 126 | bool result = false; 127 | 128 | // Loop through triggers 129 | for (unsigned int i = 0; i < triggers.size(); i++) 130 | { 131 | // Is this a valid trigger? 132 | if (triggers[i]->parsedOkay) 133 | { 134 | // Found at least one 135 | result = true; 136 | break; 137 | } 138 | } 139 | 140 | return result; 141 | } 142 | 143 | // Does this clock have a valid start trigger? 144 | bool AnimationClock::HasValidStartTrigger() 145 | { 146 | bool result = false; 147 | 148 | // Loop through triggers 149 | for (unsigned int i = 0; i < triggers.size(); i++) 150 | { 151 | // Is this a valid start trigger? 152 | if (triggers[i]->parsedOkay && 153 | triggers[i]->triggeredFunction == "start") 154 | { 155 | // Found one 156 | result = true; 157 | break; 158 | } 159 | } 160 | 161 | return result; 162 | } 163 | 164 | void AnimationClock::SetParameter(const std::string& parameter, const std::string& value) 165 | { 166 | // Duration 167 | if (parameter == "duration" || 168 | parameter == "dur") 169 | { 170 | if (debug) 171 | { 172 | outFile << "\n// Found animation duration parameter"; 173 | } 174 | 175 | // Parse a float value for the duration parameter 176 | this->duration = (float)strtod(value.c_str(), NULL); 177 | 178 | if (debug) 179 | { 180 | outFile << "\n// duration = " << setiosflags(ios::fixed) << setprecision(2) << 181 | this->duration << " seconds"; 182 | } 183 | } 184 | 185 | // Delay 186 | if (parameter == "delay" || 187 | parameter == "del") 188 | { 189 | if (debug) 190 | { 191 | outFile << "\n// Found animation delay parameter"; 192 | } 193 | 194 | // Parse a float value for the delay parameter 195 | this->delay = (float)strtod(value.c_str(), NULL); 196 | 197 | if (debug) 198 | { 199 | outFile << "\n// delay = " << setiosflags(ios::fixed) << setprecision(2) << 200 | this->delay << " seconds"; 201 | } 202 | } 203 | 204 | // Direction 205 | if (parameter == "direction" || 206 | parameter == "dir") 207 | { 208 | if (debug) 209 | { 210 | outFile << "\n// Found animation direction parameter"; 211 | } 212 | 213 | // Parse value 214 | if (value == "none" || 215 | value == "n") 216 | { 217 | this->direction = AnimationClock::kNone; 218 | } 219 | else if (value == "forward" || 220 | value == "f") 221 | { 222 | this->direction = AnimationClock::kForward; 223 | } 224 | else if (value == "backward" || 225 | value == "b") 226 | { 227 | this->direction = AnimationClock::kBackward; 228 | } 229 | } 230 | 231 | // Reverses? 232 | if (parameter == "reverses" || 233 | parameter == "rev") 234 | { 235 | if (debug) 236 | { 237 | outFile << "\n// Found animation reverses parameter"; 238 | } 239 | 240 | if (value == "yes" || 241 | value == "y") 242 | { 243 | this->reverses = true; 244 | } 245 | else if (value == "no" || 246 | value == "n") 247 | { 248 | this->reverses = false; 249 | } 250 | } 251 | 252 | // Iterations 253 | if (parameter == "iterations" || 254 | parameter == "iter") 255 | { 256 | if (debug) 257 | { 258 | outFile << "\n// Found animation iterations parameter"; 259 | } 260 | 261 | // Infinite? 262 | if (value == "infinite" || 263 | value == "i") 264 | { 265 | // 0 = infinite 266 | this->iterations = 0; 267 | } 268 | else 269 | { 270 | // Parse a unsigned long int value for the iteration parameter 271 | this->iterations = strtoul(value.c_str(), NULL, 0); 272 | 273 | if (debug) 274 | { 275 | outFile << "\n// iterations = " << setiosflags(ios::fixed) << setprecision(2) << 276 | this->iterations; 277 | } 278 | } 279 | } 280 | 281 | // Timing function 282 | if (parameter == "timing-function" || 283 | parameter == "t-f") 284 | { 285 | if (debug) 286 | { 287 | outFile << "\n// Found animation timing function parameter"; 288 | } 289 | 290 | // Short-cut value? 291 | if (value == "linear" || 292 | value == "l") 293 | { 294 | // Set to linear 295 | this->timingFunction = "linear"; 296 | } 297 | else 298 | { 299 | // Get the associated timing function name 300 | std::string timingFunctionName = value; 301 | 302 | // Clean the name for a function 303 | // TODO: Should we convert to camel-case? Doesn't seem like we should, since this will be in the user's JavaScript 304 | CleanString(timingFunctionName, false); 305 | 306 | if (debug) 307 | { 308 | outFile << "\n// Timing function name = " << timingFunctionName; 309 | } 310 | 311 | // Set function name 312 | this->timingFunction = timingFunctionName; 313 | } 314 | } 315 | 316 | // Multiplier 317 | if (parameter == "multiplier" || 318 | parameter == "mult") 319 | { 320 | if (debug) 321 | { 322 | outFile << "\n// Found animation multiplier parameter"; 323 | } 324 | 325 | // Parse a float value for the multiplier parameter 326 | this->multiplier = (float)strtod(value.c_str(), NULL); 327 | 328 | if (debug) 329 | { 330 | outFile << "\n// multiplier = " << setiosflags(ios::fixed) << setprecision(2) << 331 | this->multiplier; 332 | } 333 | } 334 | 335 | // Offset (as a percentage) 336 | if (parameter == "offset" || 337 | parameter == "off") 338 | { 339 | if (debug) 340 | { 341 | outFile << "\n// Found animation offset parameter"; 342 | } 343 | 344 | // Parse a float value for the offset parameter 345 | this->offset = (float)strtod(value.c_str(), NULL); 346 | 347 | if (debug) 348 | { 349 | outFile << "\n// offset = " << setiosflags(ios::fixed) << setprecision(2) << 350 | this->offset; 351 | } 352 | } 353 | 354 | // Trigger related? 355 | if (IsValidTrigger(parameter)) 356 | { 357 | if (debug) 358 | { 359 | outFile << "\n// Found trigger parameter"; 360 | } 361 | 362 | // Create new trigger 363 | Trigger* trigger = new Trigger(); 364 | 365 | // Set the trigger parameter 366 | trigger->SetParameter(parameter, value); 367 | 368 | // Did the trigger parse okay? 369 | if (trigger->parsedOkay) 370 | { 371 | // Add it to the list 372 | triggers.push_back(trigger); 373 | } 374 | else 375 | { 376 | // Delete it 377 | delete trigger; 378 | } 379 | } 380 | } 381 | 382 | // Is the parameter name a valid trigger? 383 | bool AnimationClock::IsValidTrigger(const std::string& parameter) 384 | { 385 | return (parameter == "reset" || 386 | parameter == "start" || 387 | parameter == "restart" || 388 | parameter == "stop" || 389 | parameter == "toggle" || 390 | parameter == "rewind" || 391 | parameter == "fast-forward" || 392 | parameter == "reverse"); 393 | } 394 | -------------------------------------------------------------------------------- /Source/AnimationClock.h: -------------------------------------------------------------------------------- 1 | // AnimationClock.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | 24 | #ifndef ANIMATIONCLOCK_H 25 | #define ANIMATIONCLOCK_H 26 | 27 | #include "IllustratorSDK.h" 28 | #include "Utility.h" 29 | #include "Trigger.h" 30 | 31 | namespace CanvasExport 32 | { 33 | // Globals 34 | extern ofstream outFile; 35 | extern bool debug; 36 | 37 | // Represents an animation clock 38 | class AnimationClock 39 | { 40 | private: 41 | 42 | public: 43 | 44 | AnimationClock(); 45 | ~AnimationClock(); 46 | 47 | enum Direction { kBackward = -1, kNone = 0, kForward = 1 }; 48 | 49 | std::string name; // Name of this clock 50 | float duration; // Clock duration (in seconds) 51 | float delay; // Initial delay (in seconds) 52 | Direction direction; // Direction 53 | bool reverses; // Does the clock automatically reverse? 54 | unsigned long iterations; // Number of iterations (0 = infinite) 55 | std::string timingFunction; // Name of the timing function 56 | std::string rangeExpression; // Upper range JavaScript expression (i.e. "(2.0 * Math.PI)") 57 | float multiplier; // Clock value multiplier 58 | float offset; // Offset after rangeExpression and multiplier (as a percentage of the range) 59 | 60 | // Triggers 61 | std::vector triggers; // Reference to animation clock triggers 62 | 63 | void JSClockInit(const std::string& objectName); 64 | void JSClockTriggerInit(const std::string& objectName); 65 | void JSClockStart(const std::string& objectName); 66 | void JSClockTick(const std::string& objectName); 67 | void SetParameter(const std::string& parameter, const std::string& value); 68 | bool HasValidTriggers(); 69 | bool HasValidStartTrigger(); 70 | bool IsValidTrigger(const std::string& parameter); 71 | }; 72 | } 73 | #endif 74 | -------------------------------------------------------------------------------- /Source/AnimationFunction.cpp: -------------------------------------------------------------------------------- 1 | // AnimationFunction.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "AnimationFunction.h" 25 | 26 | using namespace CanvasExport; 27 | 28 | AnimationFunction::AnimationFunction() 29 | { 30 | // Initialize Function 31 | this->type = Function::kAnimationFunction; 32 | 33 | // Initialize AnimationFunction 34 | this->index = 0; 35 | this->rootArtHandle = nullptr; 36 | this->segmentLength = 0.0f; 37 | 38 | // Initialize path animation clock 39 | this->pathClock.name = "pathClock"; 40 | this->pathClock.direction = AnimationClock::kForward; 41 | this->pathClock.rangeExpression = "this.linear.length - 1"; 42 | } 43 | 44 | AnimationFunction::~AnimationFunction() 45 | { 46 | } 47 | 48 | // Render the animation function/object initialization 49 | void AnimationFunction::RenderInit(const AIRealRect& documentBounds) 50 | { 51 | // Begin function block 52 | outFile << "\n\n function " << name << "() {"; 53 | 54 | outFile << "\n\n // Control and anchor points"; 55 | outFile << "\n this.points = ["; 56 | 57 | // Re-set matrix based on document 58 | // TODO: Need to make this more isolated/encapsulated 59 | sAIRealMath->AIRealMatrixSetIdentity(&canvas->currentState->internalTransform); 60 | sAIRealMath->AIRealMatrixConcatScale(&canvas->currentState->internalTransform, 1, -1); 61 | sAIRealMath->AIRealMatrixConcatTranslate(&canvas->currentState->internalTransform, - 1 * documentBounds.left, documentBounds.top); 62 | 63 | // Render animation 64 | RenderArt(rootArtHandle, 1); 65 | 66 | outFile << "\n ];"; 67 | 68 | // Add arc-length data 69 | ArcLength(1); 70 | 71 | // Other values 72 | outFile << "\n\n this.lastValue = -1.0;"; 73 | outFile << "\n this.x = 0;"; 74 | outFile << "\n this.y = 0;"; 75 | outFile << "\n this.orientation = 0.0;"; 76 | 77 | RenderClockInit(); 78 | 79 | outFile << "\n\n // Update function"; 80 | outFile << "\n this.update = updatePath;"; 81 | //outFile << "\n\n // Establish orientation"; 82 | //outFile << "\n this.update();"; 83 | 84 | // End function block 85 | outFile << "\n }"; 86 | } 87 | 88 | void AnimationFunction::RenderClockInit() 89 | { 90 | pathClock.JSClockInit("this"); 91 | } 92 | 93 | void AnimationFunction::RenderTriggerInit() 94 | { 95 | stringstream animation; 96 | animation << "animations[" << index << "]"; 97 | pathClock.JSClockTriggerInit(animation.str()); 98 | } 99 | 100 | void AnimationFunction::RenderClockStart() 101 | { 102 | stringstream animation; 103 | animation << "animations[" << index << "]"; 104 | pathClock.JSClockStart(animation.str()); 105 | } 106 | 107 | void AnimationFunction::RenderClockTick() 108 | { 109 | // Do nothing 110 | } 111 | 112 | // Crawl the art tree, but only look for paths 113 | // The goal is to output just the path segments 114 | // Also, we output in order...unlike rendering other artwork 115 | void AnimationFunction::RenderArt(AIArtHandle artHandle, unsigned int depth) 116 | { 117 | do 118 | { 119 | // Is this art visible? 120 | AIBoolean isArtVisible = false; 121 | ai::int32 attr = 0; 122 | sAIArt->GetArtUserAttr(artHandle, kArtHidden, &attr); 123 | isArtVisible = !((attr &kArtHidden) == kArtHidden); 124 | 125 | // Only render if art is visible 126 | if (isArtVisible) 127 | { 128 | // Get type 129 | short artType = 0; 130 | sAIArt->GetArtType(artHandle, &artType); 131 | 132 | // Process based on art type 133 | switch (artType) 134 | { 135 | case kGroupArt: 136 | { 137 | // Render this sub-group 138 | RenderGroupArt(artHandle, depth); 139 | break; 140 | } 141 | case kCompoundPathArt: 142 | { 143 | RenderCompoundPathArt(artHandle, depth); 144 | break; 145 | } 146 | case kPathArt: 147 | { 148 | RenderPathArt(artHandle, depth); 149 | break; 150 | } 151 | } 152 | } 153 | 154 | // Find the next sibling 155 | sAIArt->GetArtSibling(artHandle, &artHandle); 156 | } 157 | while (artHandle != nullptr); 158 | } 159 | 160 | void AnimationFunction::RenderGroupArt(AIArtHandle artHandle, unsigned int depth) 161 | { 162 | // Get the first art element in the group 163 | AIArtHandle childArtHandle = nullptr; 164 | sAIArt->GetArtFirstChild(artHandle, &childArtHandle); 165 | 166 | // Render this sub-group 167 | RenderArt(childArtHandle, depth + 1); 168 | } 169 | 170 | void AnimationFunction::RenderCompoundPathArt(AIArtHandle artHandle, unsigned int depth) 171 | { 172 | // Get the first art element in the group 173 | AIArtHandle childArtHandle = nullptr; 174 | sAIArt->GetArtFirstChild(artHandle, &childArtHandle); 175 | 176 | // Render this sub-group 177 | RenderPathArt(childArtHandle, depth + 1); 178 | } 179 | 180 | void AnimationFunction::RenderPathArt(AIArtHandle artHandle, unsigned int depth) 181 | { 182 | // Skip if this path is a "guide" 183 | AIBoolean isGuide = false; 184 | sAIPath->GetPathGuide(artHandle, &isGuide); 185 | if (!isGuide) 186 | { 187 | // Is this art part of a compound path? 188 | AIBoolean isCompound = false; 189 | ai::int32 attr = 0; 190 | sAIArt->GetArtUserAttr(artHandle, kArtPartOfCompound, &attr); 191 | isCompound = ((attr &kArtPartOfCompound) == kArtPartOfCompound); 192 | 193 | do 194 | { 195 | // Write each path as a figure 196 | RenderPathFigure(artHandle, depth); 197 | 198 | // If this is a compound path, get the next sibling 199 | if (isCompound) 200 | { 201 | sAIArt->GetArtSibling(artHandle, &artHandle); 202 | } 203 | 204 | } 205 | while (isCompound && (artHandle != nullptr)); 206 | } 207 | } 208 | 209 | // Output a single path and its segments (call multiple times for a compound path) 210 | // There is a GetPathBezier command that might make this easier/more straightforward 211 | void AnimationFunction::RenderPathFigure(AIArtHandle artHandle, unsigned int depth) 212 | { 213 | // Is this a closed path? 214 | AIBoolean pathClosed = false; 215 | sAIPath->GetPathClosed(artHandle, &pathClosed); 216 | 217 | // Get the path starting point 218 | AIPathSegment segment; 219 | sAIPath->GetPathSegments(artHandle, 0, 1, &segment); 220 | 221 | // Remember the first segment, in case we have to create an extra segment to close the figure 222 | AIPathSegment firstSegment = segment; 223 | 224 | // Transform starting point 225 | TransformPoint(segment.p); 226 | TransformPoint(segment.in); 227 | TransformPoint(segment.out); 228 | 229 | // Move to the first point 230 | //fprintf(m_fp, "\n%s%s.moveTo(%.1f, %.1f);", Indent(depth), canvas->contextName.c_str(), x, y); 231 | 232 | // How many segments are in this path? 233 | short segmentCount = 0; 234 | sAIPath->GetPathSegmentCount(artHandle, &segmentCount); 235 | 236 | // Track the last out point 237 | AIPathSegment previousSegment = segment; 238 | 239 | // Loop through each segment 240 | for (short segmentIndex = 1; segmentIndex < segmentCount; segmentIndex++) 241 | { 242 | sAIPath->GetPathSegments(artHandle, segmentIndex, 1, &segment); 243 | 244 | RenderSegment(previousSegment, segment, depth); 245 | 246 | previousSegment = segment; 247 | } 248 | 249 | // Handle closing segment 250 | if (pathClosed) 251 | { 252 | // Create "phantom" extra segment to accomodate curve 253 | RenderSegment(previousSegment, firstSegment, depth); 254 | } 255 | } 256 | 257 | void AnimationFunction::RenderSegment(AIPathSegment& previousSegment, AIPathSegment& segment, unsigned int depth) 258 | { 259 | // Transform points 260 | TransformPoint(segment.p); 261 | TransformPoint(segment.in); 262 | TransformPoint(segment.out); 263 | 264 | AIReal x1 = previousSegment.out.h; 265 | AIReal y1 = previousSegment.out.v; 266 | AIReal x2 = segment.in.h; 267 | AIReal y2 = segment.in.v; 268 | 269 | // Is this a straight line segment? 270 | AIBoolean isLine = ((previousSegment.p.h == previousSegment.out.h && previousSegment.p.v == previousSegment.out.v) && 271 | (segment.p.h == segment.in.h && segment.p.v == segment.in.v)); 272 | if (isLine) 273 | { 274 | // Optimize point locations 275 | x1 = ((segment.p.h - previousSegment.p.h) * 0.33f) + previousSegment.p.h; 276 | y1 = ((segment.p.v - previousSegment.p.v) * 0.33f) + previousSegment.p.v; 277 | x2 = ((segment.p.h - previousSegment.p.h) * 0.66f) + previousSegment.p.h; 278 | y2 = ((segment.p.v - previousSegment.p.v) * 0.66f) + previousSegment.p.v; 279 | } 280 | 281 | // If this isn't the first segment, include separator 282 | if (beziers.size() > 0) 283 | { 284 | outFile << ","; 285 | } 286 | 287 | // Output Bezier segment 288 | outFile << "\n" << Indent(depth) << " [ " << 289 | "[" << setiosflags(ios::fixed) << setprecision(1) << previousSegment.p.h << ", " << previousSegment.p.v << "]" << 290 | ", [" << x1 << ", " << y1 << "]" << 291 | ", [" << x2 << ", " << y2 << "]" << 292 | ", [" << segment.p.h << ", " << segment.p.v << "] ]"; 293 | 294 | AIRealPoint p1; 295 | AIRealPoint p2; 296 | p1.h = x1; 297 | p1.v = y1; 298 | p2.h = x2; 299 | p2.v = y2; 300 | 301 | const AIReal FLATNESS = 1e-2f; // Adobe recommended value 302 | AIRealBezier b; 303 | sAIRealBezier->Set(&b, &previousSegment.p, &p1, &p2, &segment.p); 304 | AIReal bezierSegmentLength = sAIRealBezier->Length(&b, FLATNESS); 305 | //outFile << "\n" << Indent(depth) << " // Length = " << setiosflags(ios::fixed) << setprecision(2) << segmentLength; 306 | 307 | // Remember for later 308 | BezierInfo bi; 309 | bi.b = b; 310 | bi.length = bezierSegmentLength; 311 | beziers.push_back(bi); 312 | } 313 | 314 | void AnimationFunction::ArcLength(unsigned int depth) 315 | { 316 | const AIReal FLATNESS = 1e-2f; // Adobe recommended value 317 | 318 | // First, calculate total length of all segments 319 | AIReal totalLength = 0; 320 | AIReal shortestLength = 65535.0f; // Track the shortest length, so we can split up at least each segment once 321 | for (unsigned int i = 0; i < beziers.size(); i++) 322 | { 323 | totalLength += beziers[i].length; 324 | 325 | if (beziers[i].length < shortestLength) 326 | { 327 | shortestLength = beziers[i].length; 328 | } 329 | } 330 | 331 | outFile << "\n\n // Linear motion index"; 332 | outFile << "\n this.linear = ["; 333 | 334 | // Next, pick equally-spaced points along the total path that are at least shorter than the shortest segment 335 | unsigned int spacing = ((shortestLength * 0.9f) < 50.0f) ? (unsigned int)(shortestLength * 0.9f) : 50; 336 | if (spacing < 1) { spacing = 1; } 337 | 338 | // Remember length for debugging 339 | segmentLength = (float)spacing; 340 | 341 | const unsigned int TOTAL_POINTS = (unsigned int)(totalLength / spacing); 342 | for (unsigned int i = 0; i < (TOTAL_POINTS + 1.0f); i++) 343 | { 344 | // Find out which index contains the correct "length" 345 | AIReal totalS = (AIReal)i / (AIReal)TOTAL_POINTS; 346 | AIReal searchLength = totalS * totalLength; 347 | AIReal remainingSearchLength = searchLength; 348 | 349 | // Find correct segment 350 | size_t s = 0; 351 | for (s = 0; s < beziers.size(); s++) 352 | { 353 | if (remainingSearchLength <= beziers[s].length) 354 | { 355 | // In this segment 356 | break; 357 | } 358 | 359 | // Remove this segment's length from search 360 | remainingSearchLength -= beziers[s].length; 361 | } 362 | 363 | AIReal t; 364 | 365 | // If math didn't work out perfectly, protect against it 366 | if (s >= beziers.size()) 367 | { 368 | s = beziers.size() - 1; 369 | t = 1.0f; 370 | } 371 | else 372 | { 373 | // Now that we found the segment, find the t value within the segment 374 | sAIRealBezier->TAtLength(&beziers[s].b, remainingSearchLength, beziers[s].length, FLATNESS, &t); 375 | //outFile << "\n" << Indent(depth) << " // t at length " << setiosflags(ios::fixed) << setprecision(2) << length << " = " << t; 376 | } 377 | 378 | // Separator 379 | if (i > 0) 380 | { 381 | outFile << ", "; 382 | } 383 | 384 | // New line every once and awhile 385 | if (i % 4 == 0) 386 | { 387 | outFile << "\n" << Indent(depth) << " "; 388 | } 389 | 390 | outFile << "[" << setiosflags(ios::fixed) << setprecision(2) << 391 | s << ", " << t << ", " << totalS << "]"; 392 | } 393 | 394 | // End function block 395 | outFile << "\n ];"; 396 | 397 | outFile << "\n\n // Segment T boundaries"; 398 | outFile << "\n this.segmentT = ["; 399 | 400 | AIReal runningLength = 0.0f; 401 | for (unsigned int i = 0; i < beziers.size(); i++) 402 | { 403 | // Track running length 404 | runningLength += beziers[i].length; 405 | 406 | if (i > 0) 407 | { 408 | outFile << ", "; 409 | } 410 | outFile << setiosflags(ios::fixed) << setprecision(2) << (runningLength / totalLength); 411 | } 412 | 413 | // End block 414 | outFile << "];"; 415 | } 416 | 417 | void AnimationFunction::Bezier(const AIRealBezier& b, AIReal u, AIReal& x, AIReal& y) 418 | { 419 | x = pow(u, 3) * (b.p3.h + 3 * (b.p1.h - b.p2.h) - b.p0.h) + 3 * pow(u, 2) * (b.p0.h - 2 * b.p1.h + b.p2.h) + 3 * u * (b.p1.h - b.p0.h) + b.p0.h; 420 | y = pow(u, 3) * (b.p3.v + 3 * (b.p1.v - b.p2.v) - b.p0.v) + 3 * pow(u, 2) * (b.p0.v - 2 * b.p1.v + b.p2.v) + 3 * u * (b.p1.v - b.p0.v) + b.p0.v; 421 | } 422 | 423 | void AnimationFunction::TransformPoint(AIRealPoint& point) 424 | { 425 | sAIRealMath->AIRealMatrixXformPoint(&canvas->currentState->internalTransform, &point, &point); 426 | } 427 | 428 | void AnimationFunction::SetParameter(const std::string& parameter, const std::string& value) 429 | { 430 | // Allow path clock to parse its own parameters 431 | pathClock.SetParameter(parameter, value); 432 | } 433 | 434 | bool const AnimationFunction::HasValidTriggers() 435 | { 436 | return this->pathClock.HasValidTriggers(); 437 | } 438 | -------------------------------------------------------------------------------- /Source/AnimationFunction.h: -------------------------------------------------------------------------------- 1 | // AnimationFunction.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef ANIMATIONFUNCTION_H 24 | #define ANIMATIONFUNCTION_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Function.h" 28 | #include "Canvas.h" 29 | #include "Utility.h" 30 | #include "AnimationClock.h" 31 | 32 | namespace CanvasExport 33 | { 34 | // Globals 35 | extern ofstream outFile; 36 | extern bool debug; 37 | 38 | struct BezierInfo 39 | { 40 | AIRealBezier b; // Bezier 41 | AIReal length; // Segment length 42 | }; 43 | 44 | /// Represents a JavaScript animation function 45 | class AnimationFunction : public Function 46 | { 47 | private: 48 | 49 | public: 50 | 51 | AnimationFunction(); 52 | ~AnimationFunction(); 53 | 54 | AnimationClock pathClock; // Clock for the animation path 55 | 56 | unsigned int index; // JavaScript animation array index 57 | AIArtHandle rootArtHandle; // Handle to art tree 58 | std::vector beziers; // Bezier segments (for arc-length calculations) 59 | float segmentLength; // Computed linear segment length 60 | 61 | void RenderInit(const AIRealRect& documentBounds); // Initialize animation 62 | virtual void RenderClockInit(); // Initialize animation clocks 63 | virtual void RenderTriggerInit(); // Initialize animation clock triggers 64 | virtual void RenderClockStart(); // Start animation clocks 65 | virtual void RenderClockTick(); // Tick animation clocks 66 | virtual void SetParameter(const std::string& parameter, const std::string& value); 67 | virtual bool const HasValidTriggers(); 68 | 69 | void RenderArt(AIArtHandle artHandle, unsigned int depth); 70 | void RenderGroupArt(AIArtHandle artHandle, unsigned int depth); 71 | void RenderCompoundPathArt(AIArtHandle artHandle, unsigned int depth); 72 | void RenderPathArt(AIArtHandle artHandle, unsigned int depth); 73 | void RenderPathFigure(AIArtHandle artHandle, unsigned int depth); 74 | void RenderSegment(AIPathSegment& previousSegment, AIPathSegment& segment, unsigned int depth); 75 | void TransformPoint(AIRealPoint& point); 76 | void Bezier(const AIRealBezier& b, AIReal u, AIReal& x, AIReal& y); 77 | void ArcLength(unsigned int depth); 78 | }; 79 | } 80 | #endif 81 | -------------------------------------------------------------------------------- /Source/Canvas.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeswanson/Ai2Canvas/bd48b6f3b438cf2f1781f44cbfa57c77f41f0ef1/Source/Canvas.cpp -------------------------------------------------------------------------------- /Source/Canvas.h: -------------------------------------------------------------------------------- 1 | // Canvas.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef CANVAS_H 24 | #define CANVAS_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Ai2CanvasSuites.h" 28 | #include "State.h" 29 | #include "Utility.h" 30 | #include 31 | #include 32 | #include "DocumentResources.h" 33 | 34 | // Accommodate color component type based on SDK version 35 | #if kPluginInterfaceVersion > kPluginInterfaceVersion16001 36 | typedef AIFloatSampleComponent SampleComponent; 37 | #else 38 | typedef AISampleComponent SampleComponent; 39 | #endif 40 | 41 | namespace CanvasExport 42 | { 43 | // Globals 44 | extern ofstream outFile; 45 | extern bool debug; 46 | 47 | // Drop shadow parameters 48 | // NOTE: Should this move to State? That's where it is in the canvas spec. 49 | struct DropShadow 50 | { 51 | AIReal horz; // Horizontal offset 52 | AIReal vert; // Vertical offset 53 | AIReal blur; // Blur amount 54 | AIFillStyle shadowStyle; // Fill style 55 | AIReal opac; // Opacity 56 | }; 57 | 58 | // Handy structure to maintain glyph state 59 | // TODO: Evaluate a better (cleaner) way to do this 60 | struct GlyphState 61 | { 62 | AIReal fontSize; 63 | AIReal verticalScale; 64 | AIReal horizontalScale; 65 | AIRealMatrix glyphMatrix; 66 | AIBoolean textFilled; 67 | AIBoolean textStroked; 68 | AIColor fillColor; 69 | std::string fillStyle; 70 | std::string strokeStyle; 71 | std::string fontName; 72 | std::string fontStyleName; 73 | AIStrokeStyle strokeStyleValue; 74 | }; 75 | 76 | /// Represents a HTML5 canvas element 77 | class Canvas 78 | { 79 | private: 80 | 81 | public: 82 | 83 | DocumentResources* documentResources; // Document resources 84 | std::string id; // Canvas element ID 85 | AIReal width; // Width 86 | AIReal height; // Height 87 | AIBoolean isHidden; // Is this canvas hidden (i.e. for patterns)? 88 | std::string contextName; // Name of the drawing context 89 | State* currentState; // Pointer to the current drawing state 90 | std::vector states; // Stack of drawing states 91 | AIPathStyle pathfinderStyle; // Style for PathFinder artwork 92 | AIBoolean usePathfinderStyle; // Track special kPluginArt/Pathfinder style (seems "hacky") 93 | std::vector breadcrumbs; // Path to the artwork 94 | 95 | Canvas(const std::string& id, DocumentResources* documentResources); 96 | ~Canvas(); 97 | 98 | void PushState(); 99 | void PopState(); 100 | void DebugInfo(); 101 | 102 | void AddBreadcrumb(const std::string& artName, unsigned int depth); 103 | void RemoveBreadcrumb(); 104 | 105 | void Render(); 106 | void RenderImages(); 107 | 108 | void RenderArt(AIArtHandle artHandle, unsigned int depth); 109 | void ParseArtStyle(AIArtHandle artHandle, unsigned int depth, ASInt32& postEffectCount, 110 | AIBlendingMode& blendingMode, AIBoolean& hasDropShadow, DropShadow& dropShadow); 111 | void SetContextDrawingState(unsigned int depth); 112 | void RenderDropShadow(const DropShadow& dropShadow, unsigned int depth); 113 | void RenderUnsupportedArt(AIArtHandle artHandle, const std::string& fileName, unsigned int depth); 114 | void RasterizeArtToPNG(AIArtHandle artHandle, const std::string& path); 115 | void GetPNGDimensions(const std::string& path, unsigned int& width, unsigned int& height); 116 | uint32_t ReverseInt(uint32_t i); 117 | AIReal GetJPGDPI(const std::string& path); 118 | uint16_t ReverseInt(uint16_t i); 119 | void ReportRasterRecordInfo(const AIRasterRecord& rasterRecord); 120 | void ReportColorSpaceInfo(ai::int16 colorSpace); 121 | void RenderGroupArt(AIArtHandle artHandle, unsigned int depth); 122 | void RenderPluginArt(AIArtHandle artHandle, unsigned int depth); 123 | void RenderSymbolArt(AIArtHandle artHandle, unsigned int depth); 124 | void RenderCompoundPathArt(AIArtHandle artHandle, unsigned int depth); 125 | void RenderPathArt(AIArtHandle artHandle, unsigned int depth); 126 | void RenderPathFigure(AIArtHandle artHandle, unsigned int depth); 127 | void RenderSegment(AIPathSegment& previousSegment, AIPathSegment& segment, unsigned int depth); 128 | void RenderPathStyle(const AIPathStyle& style, unsigned int depth); 129 | void RenderPlacedArt(AIArtHandle artHandle, unsigned int depth); 130 | void RenderRasterArt(AIArtHandle artHandle, unsigned int depth); 131 | void RenderMidPointColor(const AIColor& color1, AIReal alpha1, const AIColor& color2, AIReal alpha2); 132 | void RenderGradient(const AIGradientStyle& gradientStyle, unsigned int depth); 133 | void RenderGradientStops(const AIGradientStyle& gradientStyle, unsigned int depth); 134 | void RenderFillInfo(const AIColor& fillColor, unsigned int depth); 135 | void GetFillStyle(const AIColor& color, AIReal alpha, std::string& fillStyle); 136 | void ReportPatternStyleInfo(const AIPatternStyle& patternStyle); 137 | void RenderStrokeInfo(const AIStrokeStyle& strokeStyle, unsigned int depth); 138 | void RenderTextFrameArt(AIArtHandle artHandle, unsigned int depth); 139 | void RenderGlyphRuns(AIArtHandle textFrameArt, unsigned int depth); 140 | void RenderGlyphRun(char *contents, const GlyphState& glyphState, unsigned int depth); 141 | AIBoolean GlyphStatesMatch(const GlyphState& state1, const GlyphState& state2); 142 | void GetGlyphState(const ATE::IGlyphRun& glyphRun, GlyphState& glyphState, const AIRealMatrix& textFrameMatrix, unsigned int depth); 143 | void ReportGlyphRunInfo(const ATE::IGlyphRun& glyphRun); 144 | void ReportCharacterFeatures(const ATE::ICharFeatures& features); 145 | std::string GetColor(const AIColor& color, AIReal alpha); 146 | void ConvertColorToRGB(const AIColor& sourceColor, AIColor& rbgColor); 147 | void TransformRect(AIRealRect& rect); 148 | void TransformPoint(AIRealPoint& point); 149 | void TransformPointWithMatrix(AIRealPoint& point, const AIRealMatrix& matrix); 150 | }; 151 | } 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /Source/CanvasCollection.cpp: -------------------------------------------------------------------------------- 1 | // CanvasCollection.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "CanvasCollection.h" 25 | 26 | using namespace CanvasExport; 27 | 28 | CanvasCollection::CanvasCollection() 29 | { 30 | } 31 | 32 | CanvasCollection::~CanvasCollection() 33 | { 34 | // Clear canvases 35 | for (unsigned int i = 0; i < canvases.size(); i++) 36 | { 37 | // Remove instance 38 | delete canvases[i]; 39 | } 40 | 41 | } 42 | 43 | void CanvasCollection::Render() 44 | { 45 | // Render canvases 46 | for (unsigned int i = 0; i < canvases.size(); i++) 47 | { 48 | // Render 49 | canvases[i]->Render(); 50 | } 51 | } 52 | 53 | // Find a canvas, returns NULL if not found 54 | Canvas* CanvasCollection::Find(const std::string& id) 55 | { 56 | Canvas* result = nullptr; 57 | 58 | // Loop through canvases 59 | for (unsigned int i = 0; i < canvases.size(); i++) 60 | { 61 | // Do the IDs match? 62 | if (canvases[i]->id == id) 63 | { 64 | // Found a match 65 | result = canvases[i]; 66 | break; 67 | } 68 | } 69 | 70 | // Return result 71 | return result; 72 | } 73 | 74 | // Adds a new canvas with a given ID and context name 75 | Canvas* CanvasCollection::Add(const std::string& id, const std::string& contextName, DocumentResources* documentResources) 76 | { 77 | // Create new canvas with ID 78 | Canvas* canvas = new Canvas(id, documentResources); 79 | 80 | // Set context name 81 | canvas->contextName = contextName; 82 | 83 | // Add to array 84 | canvases.push_back(canvas); 85 | 86 | // Return 87 | return canvas; 88 | } 89 | -------------------------------------------------------------------------------- /Source/CanvasCollection.h: -------------------------------------------------------------------------------- 1 | // CanvasCollection.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef CANVASCOLLECTION_H 24 | #define CANVASCOLLECTION_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Canvas.h" 28 | #include "Utility.h" 29 | 30 | namespace CanvasExport 31 | { 32 | // Globals 33 | extern ofstream outFile; 34 | extern bool debug; 35 | 36 | /// Represents a collection of canvases 37 | class CanvasCollection 38 | { 39 | private: 40 | 41 | std::vector canvases; // Collection of canvas pointers 42 | 43 | public: 44 | 45 | CanvasCollection(); 46 | ~CanvasCollection(); 47 | 48 | void Render(); 49 | Canvas* Add(const std::string& id, const std::string& contextName, DocumentResources* documentResources); 50 | Canvas* Find(const std::string& id); 51 | }; 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /Source/Document.h: -------------------------------------------------------------------------------- 1 | // Document.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef DOCUMENT_H 24 | #define DOCUMENT_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Ai2CanvasSuites.h" 28 | #include "Canvas.h" 29 | #include "CanvasCollection.h" 30 | #include "Layer.h" 31 | #include "DocumentResources.h" 32 | #include "FunctionCollection.h" 33 | 34 | AIBoolean ProgressProc(long current, long total); 35 | 36 | namespace CanvasExport 37 | { 38 | // Globals 39 | extern ofstream outFile; 40 | extern bool debug; 41 | 42 | /// Represents a document 43 | class Document 44 | { 45 | private: 46 | 47 | CanvasCollection canvases; 48 | FunctionCollection functions; 49 | 50 | void SetDocumentBounds(); 51 | void ParseFolderPath(const std::string& pathName); 52 | void RenderDocument(); 53 | void ScanDocument(); 54 | void ScanLayer(Layer& layer); 55 | void ScanLayerArtwork(AIArtHandle artHandle, unsigned int depth, Layer& layer); 56 | void ParseLayers(); 57 | void ParseLayerName(const Layer& layer, std::string& name, std::string& options); 58 | bool HasAnimationOption(const std::vector& options); 59 | void RenderAnimations(); 60 | void SetFunctionOptions(const std::vector& options, Function& function); 61 | void DebugClockJS(); 62 | void DebugAnimationPathJS(); 63 | void CreateAnimationFile(); 64 | void OutputScriptHeader(ofstream& file); 65 | void OutputAnimationFunctions(ofstream& file); 66 | void OutputClockFunctions(ofstream& file); 67 | void OutputTimingFunctions(ofstream& file); 68 | void RenderSymbolFunctions(); 69 | void RenderPatternFunction(); 70 | void DebugInfo(); 71 | 72 | public: 73 | 74 | Document(const std::string& pathName); 75 | ~Document(); 76 | 77 | DocumentResources resources; // Document resources 78 | 79 | std::vector layers; // Layers 80 | Canvas* canvas; // Main document canvas 81 | std::string fileName; // Output file name 82 | AIRealRect documentBounds; // Document bounds (for all visible layers that will be exported) 83 | bool hasAnimation; // Does this document have any animation? Could be rotation on a draw function or animation paths. 84 | 85 | void Render(); 86 | 87 | }; 88 | 89 | } 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /Source/DocumentResources.cpp: -------------------------------------------------------------------------------- 1 | // DocumentResources.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "DocumentResources.h" 25 | 26 | using namespace CanvasExport; 27 | 28 | DocumentResources::DocumentResources() 29 | { 30 | // Initialize DocumentResources 31 | this->folderPath = ""; 32 | } 33 | 34 | DocumentResources::~DocumentResources() 35 | { 36 | } 37 | -------------------------------------------------------------------------------- /Source/DocumentResources.h: -------------------------------------------------------------------------------- 1 | // DocumentResources.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef DOCUMENTRESOURCES_H 24 | #define DOCUMENTRESOURCES_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Utility.h" 28 | #include "ImageCollection.h" 29 | #include "PatternCollection.h" 30 | 31 | namespace CanvasExport 32 | { 33 | // Globals 34 | extern ofstream outFile; 35 | extern bool debug; 36 | 37 | /// Represents the resources for a document 38 | class DocumentResources 39 | { 40 | private: 41 | 42 | public: 43 | 44 | DocumentResources(); 45 | ~DocumentResources(); 46 | 47 | ImageCollection images; 48 | PatternCollection patterns; 49 | std::string folderPath; // Path to output folder 50 | 51 | }; 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /Source/DrawFunction.cpp: -------------------------------------------------------------------------------- 1 | // DrawFunction.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "DrawFunction.h" 25 | 26 | using namespace CanvasExport; 27 | 28 | DrawFunction::DrawFunction() 29 | { 30 | // Initialize Function 31 | this->type = Function::kDrawFunction; 32 | 33 | // Initialize DrawFunction 34 | this->requestedName = ""; 35 | this->hasGradients = false; 36 | this->hasPatterns = false; 37 | this->hasAlpha = false; 38 | this->animationFunction = nullptr; 39 | this->animationFunctionName = ""; 40 | this->follow = false; 41 | this->followOrientation = 0.0f; 42 | this->rasterizeFileName = ""; 43 | this->crop = false; 44 | 45 | // Initialize rotate animation clock 46 | this->rotateClock.name = "rotateClock"; 47 | this->rotateClock.rangeExpression = "2.0 * Math.PI"; 48 | 49 | // Initialize scale animation clock 50 | this->scaleClock.name = "scaleClock"; 51 | this->scaleClock.rangeExpression = "1.0"; 52 | 53 | // Initialize alpha animation clock 54 | this->alphaClock.name = "alphaClock"; 55 | this->alphaClock.rangeExpression = "1.0"; 56 | } 57 | 58 | DrawFunction::~DrawFunction() 59 | { 60 | } 61 | 62 | bool const DrawFunction::HasValidTriggers() 63 | { 64 | return (this->rotateClock.HasValidTriggers() || 65 | this->scaleClock.HasValidTriggers() || 66 | this->alphaClock.HasValidTriggers()); 67 | } 68 | 69 | void DrawFunction::RenderClockInit() 70 | { 71 | // Initialize rotation clock 72 | rotateClock.JSClockInit(name); 73 | 74 | // Initialize scale clock 75 | 76 | // Firefox 3.x won't allow a 0 scale value, so protect for that here by adding a very small offset 77 | if (scaleClock.offset <= 0) 78 | { 79 | // Set to very small offset (note that Number.MIN_VALUE will not work) 80 | scaleClock.offset = 0.0001f; 81 | } 82 | scaleClock.JSClockInit(name); 83 | 84 | // Initialize alpha clock 85 | alphaClock.JSClockInit(name); 86 | 87 | // Do we have a follow orientation? 88 | if (follow) 89 | { 90 | // Output follow orientation 91 | outFile << "\n " << name << ".followOrientation = " << setiosflags(ios::fixed) << setprecision(2) << 92 | followOrientation << " * Math.PI / 180.0;"; 93 | } 94 | } 95 | 96 | void DrawFunction::RenderTriggerInit() 97 | { 98 | // Configure rotation clock triggers 99 | rotateClock.JSClockTriggerInit(name); 100 | 101 | // Configure scale clock triggers 102 | scaleClock.JSClockTriggerInit(name); 103 | 104 | // Configure alpha clock triggers 105 | alphaClock.JSClockTriggerInit(name); 106 | } 107 | 108 | // Outputs correct JavaScript to start a clock immediately (if there is no "start" trigger defined) 109 | void DrawFunction::RenderClockStart() 110 | { 111 | // Start rotation clock 112 | rotateClock.JSClockStart(name); 113 | 114 | // Start scale clock 115 | scaleClock.JSClockStart(name); 116 | 117 | // Start alpha clock 118 | alphaClock.JSClockStart(name); 119 | } 120 | 121 | void DrawFunction::RenderClockTick() 122 | { 123 | // Tick rotation 124 | rotateClock.JSClockTick(name); 125 | 126 | // Tick scale 127 | scaleClock.JSClockTick(name); 128 | 129 | // Tick alpha 130 | alphaClock.JSClockTick(name); 131 | } 132 | 133 | void DrawFunction::RenderDrawFunctionCall(const AIRealRect& documentBounds) 134 | { 135 | // New line 136 | outFile << "\n"; 137 | 138 | // Does this draw function have any animation? 139 | if (animationFunction || 140 | rotateClock.direction != AnimationClock::kNone || 141 | scaleClock.direction != AnimationClock::kNone || 142 | alphaClock.direction != AnimationClock::kNone) 143 | { 144 | // Save drawing context state 145 | outFile << "\n " << canvas->contextName << ".save();"; 146 | 147 | // Do we have an animation path? 148 | if (animationFunction) 149 | { 150 | // Set transform for this animation path 151 | outFile << "\n " << canvas->contextName << ".translate(animations[" << 152 | animationFunction->index << "].x, animations[" << 153 | animationFunction->index << "].y);"; 154 | 155 | // Does this draw function have a follow orientation? 156 | if (follow) 157 | { 158 | outFile << "\n " << canvas->contextName << ".rotate(" << name << 159 | ".followOrientation + animations[" << animationFunction->index << 160 | "].orientation);"; 161 | } 162 | } 163 | else 164 | { 165 | // Do we need to reposition? 166 | if (translateOrigin) 167 | { 168 | Reposition(documentBounds); 169 | } 170 | } 171 | 172 | // Do we have any rotation on the draw function? 173 | if (rotateClock.direction != AnimationClock::kNone) 174 | { 175 | outFile << "\n " << canvas->contextName << ".rotate(" << name << "." << rotateClock.name << ".value);"; 176 | } 177 | 178 | // Do we have any scale on the draw function? 179 | if (scaleClock.direction != AnimationClock::kNone) 180 | { 181 | outFile << "\n " << canvas->contextName << ".scale(" << name << "." << scaleClock.name << ".value, " << 182 | name << "." << scaleClock.name << ".value);"; 183 | } 184 | 185 | // Do we have any alpha on the draw function? 186 | if (alphaClock.direction != AnimationClock::kNone) 187 | { 188 | outFile << "\n " << canvas->contextName << ".globalAlpha = " << name << "." << alphaClock.name << ".value;"; 189 | } 190 | 191 | // Call the draw function 192 | outFile << "\n " << name << "(" << canvas->contextName << ");"; 193 | 194 | // Show origin 195 | if (debug) 196 | { 197 | outFile << "\n " << canvas->contextName << ".save();"; 198 | outFile << "\n " << canvas->contextName << ".fillStyle = \"rgb(0, 0, 255)\";"; 199 | outFile << "\n " << canvas->contextName << ".fillRect(-2.0, -2.0, 5, 5);"; 200 | outFile << "\n " << canvas->contextName << ".restore();"; 201 | } 202 | 203 | // Restore drawing context state 204 | outFile << "\n " << canvas->contextName << ".restore();"; 205 | } 206 | else 207 | { 208 | // No animation 209 | 210 | // Do we need to reposition? 211 | if (translateOrigin) 212 | { 213 | // Save drawing context state 214 | outFile << "\n " << canvas->contextName << ".save();"; 215 | 216 | Reposition(documentBounds); 217 | } 218 | 219 | // Just call the function 220 | outFile << "\n " << name << "(" << canvas->contextName << ");"; 221 | 222 | // Show origin 223 | if (debug) 224 | { 225 | outFile << "\n " << canvas->contextName << ".save();"; 226 | outFile << "\n " << canvas->contextName << ".fillStyle = \"rgb(0, 0, 255)\";"; 227 | outFile << "\n " << canvas->contextName << ".fillRect(-2.0, -2.0, 5, 5);"; 228 | outFile << "\n " << canvas->contextName << ".restore();"; 229 | } 230 | 231 | // Do we need to restore? 232 | if (translateOrigin) 233 | { 234 | // Restore drawing context state 235 | outFile << "\n " << canvas->contextName << ".restore();"; 236 | } 237 | } 238 | } 239 | 240 | // Render a drawing function 241 | void DrawFunction::RenderDrawFunction(const AIRealRect& documentBounds) 242 | { 243 | // Begin function block 244 | outFile << "\n\n function " << name << "(ctx) {"; 245 | 246 | // Need a blank line? 247 | if (hasAlpha || hasGradients || hasPatterns) 248 | { 249 | outFile << "\n"; 250 | } 251 | 252 | // Does this draw function have alpha changes? 253 | if (hasAlpha) 254 | { 255 | // Grab the alpha value (so we can use it to compute new globalAlpha values during this draw function) 256 | outFile << "\n" << Indent(0) << "var alpha = ctx.globalAlpha;"; 257 | } 258 | 259 | // Will we be encountering gradients? 260 | if (hasGradients) 261 | { 262 | outFile << "\n" << Indent(0) << "var gradient;"; 263 | } 264 | 265 | // Will we be encountering patterns? 266 | if (hasPatterns) 267 | { 268 | outFile << "\n" << Indent(0) << "var pattern;"; 269 | } 270 | 271 | /// Re-set matrix based on document 272 | sAIRealMath->AIRealMatrixSetIdentity(&canvas->currentState->internalTransform); 273 | sAIRealMath->AIRealMatrixConcatScale(&canvas->currentState->internalTransform, 1, -1); 274 | sAIRealMath->AIRealMatrixConcatTranslate(&canvas->currentState->internalTransform, - 1 * documentBounds.left, documentBounds.top); 275 | 276 | // Do we need to move the origin? 277 | if (translateOrigin) 278 | { 279 | // Calculate offsets to move function/layer to 0, 0 of document 280 | AIReal offsetH = bounds.left - documentBounds.left; 281 | AIReal offsetV = bounds.top - documentBounds.top; 282 | 283 | // Calculate requested offsets based on percentages 284 | AIReal translateH = (bounds.right - bounds.left) * translateOriginH; 285 | AIReal translateV = (bounds.top - bounds.bottom) * translateOriginV; 286 | 287 | // Modify transformation matrix for this function (and set of layers) 288 | sAIRealMath->AIRealMatrixConcatTranslate(&canvas->currentState->internalTransform, (-1 * offsetH) - translateH, offsetV - translateV); 289 | } 290 | 291 | // Are we supposed to rasterize this function? 292 | if (!rasterizeFileName.empty()) 293 | { 294 | // Rasterize the first layer 295 | // TODO: Note that this only rasterizes the first associated layer. What if this has multiple layers? 296 | 297 | // Output layer name 298 | outFile << "\n\n" << Indent(1) << "// " << name; 299 | 300 | canvas->RenderUnsupportedArt(layers[0]->artHandle, rasterizeFileName, 1); 301 | } 302 | else 303 | { 304 | // Render each layer in the function block (they're already in the correct order) 305 | for (unsigned int i = 0; i < layers.size(); i++) 306 | { 307 | // Render the art 308 | canvas->RenderArt(layers[i]->artHandle, 1); 309 | 310 | // Restore remaining state 311 | canvas->SetContextDrawingState(1); 312 | } 313 | } 314 | 315 | // End function block 316 | outFile << "\n }"; 317 | } 318 | 319 | // Output repositioning translation for a draw function 320 | void DrawFunction::Reposition(const AIRealRect& documentBounds) 321 | { 322 | // Calculate offsets to move function/layer to 0, 0 of document 323 | AIReal offsetH = bounds.left - documentBounds.left; 324 | AIReal offsetV = bounds.top - documentBounds.top; 325 | 326 | // Calculate requested offsets based on percentages 327 | AIReal translateH = (bounds.right - bounds.left) * this->translateOriginH; 328 | AIReal translateV = (bounds.top - bounds.bottom) * this->translateOriginV; 329 | 330 | // Re-positioning translation 331 | AIReal x = offsetH + translateH; 332 | AIReal y = (-1 * offsetV) + translateV; 333 | 334 | // Render the repositioning translation for this function 335 | // NOTE: This needs to happen, even if it's just "identity," since other functions may have already changed the transformation 336 | outFile << "\n " << canvas->contextName << ".translate(" << setiosflags(ios::fixed) << setprecision(1) << x << ", " << y << ");"; 337 | } 338 | 339 | void DrawFunction::SetParameter(const std::string& parameter, const std::string& value) 340 | { 341 | // Origin 342 | if (parameter == "origin" || 343 | parameter == "o") 344 | { 345 | if (debug) 346 | { 347 | outFile << "\n// Found origin parameter"; 348 | } 349 | 350 | // Short-cut values? 351 | if (value == "normal" || 352 | value == "n") 353 | { 354 | // Normal (do nothing special) 355 | this->translateOrigin = false; 356 | } 357 | else if (value == "center" || 358 | value == "c") 359 | { 360 | // Center 361 | this->translateOrigin = true; 362 | this->translateOriginH = 0.5f; 363 | this->translateOriginV = 0.5f; 364 | } 365 | else if (value == "upper-left" || 366 | value == "ul") 367 | { 368 | // Upper left 369 | this->translateOrigin = true; 370 | this->translateOriginH = 0.0f; 371 | this->translateOriginV = 0.0f; 372 | } 373 | else if (value == "upper-right" || 374 | value == "ur") 375 | { 376 | // Upper right 377 | this->translateOrigin = true; 378 | this->translateOriginH = 1.0f; 379 | this->translateOriginV = 0.0f; 380 | } 381 | else if (value == "lower-right" || 382 | value == "lr") 383 | { 384 | // Lower right 385 | this->translateOrigin = true; 386 | this->translateOriginH = 1.0f; 387 | this->translateOriginV = 1.0f; 388 | } 389 | else if (value == "lower-left" || 390 | value == "ll") 391 | { 392 | // Lower left 393 | this->translateOrigin = true; 394 | this->translateOriginH = 0.0f; 395 | this->translateOriginV = 1.0f; 396 | } 397 | else 398 | { 399 | // Can we parse two float values? 400 | std::vector originOffsets = Tokenize(value, ","); 401 | 402 | // Did we find two values? 403 | if (originOffsets.size() == 2) 404 | { 405 | // Indicate that we want to translate 406 | this->translateOrigin = true; 407 | 408 | // Set translation values 409 | this->translateOriginH = (AIReal)strtod(originOffsets[0].c_str(), NULL); 410 | this->translateOriginV = (AIReal)strtod(originOffsets[1].c_str(), NULL); 411 | 412 | if (debug) 413 | { 414 | outFile << "\n// translateH = " << setiosflags(ios::fixed) << setprecision(1) << 415 | this->translateOriginH << ", translateV = " << this->translateOriginV; 416 | } 417 | } 418 | } 419 | } 420 | 421 | // Animation path association 422 | if (parameter == "animation" || 423 | parameter == "a") 424 | { 425 | if (debug) 426 | { 427 | outFile << "\n// Found animation parameter"; 428 | } 429 | 430 | // Get the associated animation function name 431 | std::string cleanAnimationFunctionName = value; 432 | 433 | // Clean the name for a function 434 | CleanString(cleanAnimationFunctionName, true); 435 | 436 | if (debug) 437 | { 438 | outFile << "\n// Animation function name = " << cleanAnimationFunctionName; 439 | } 440 | 441 | // Store the function name as a string that we will bind after all layers have been defined 442 | this->animationFunctionName = cleanAnimationFunctionName; 443 | } 444 | 445 | // Rotation related? 446 | if (parameter.substr(0, 7) == "rotate-" || 447 | parameter.substr(0, 2) == "r-") 448 | { 449 | if (debug) 450 | { 451 | outFile << "\n// Found rotation parameters"; 452 | } 453 | 454 | // Replace with clock parameter 455 | std::string clockParameter = parameter.substr((parameter.find_first_of('-') + 1)); 456 | 457 | // Replace direction convenience values with clock values 458 | std::string clockValue = value; 459 | if (clockValue == "clockwise" || 460 | clockValue == "cw") 461 | { 462 | // Same as forward 463 | clockValue = "forward"; 464 | } 465 | else if (clockValue == "counterclockwise" || 466 | clockValue == "ccw") 467 | { 468 | // Same as backward 469 | clockValue = "backward"; 470 | } 471 | 472 | // Set the clock parameter 473 | rotateClock.SetParameter(clockParameter, clockValue); 474 | } 475 | 476 | // Scale related? 477 | if (parameter.substr(0, 6) == "scale-" || 478 | parameter.substr(0, 2) == "s-") 479 | { 480 | if (debug) 481 | { 482 | outFile << "\n// Found scale parameters"; 483 | } 484 | 485 | // Replace with clock parameter 486 | std::string clockParameter = parameter.substr((parameter.find_first_of('-') + 1)); 487 | 488 | // Replace direction convenience values with clock values 489 | std::string clockValue = value; 490 | if (clockValue == "grow" || 491 | clockValue == "g") 492 | { 493 | // Same as forward 494 | clockValue = "forward"; 495 | } 496 | else if (clockValue == "shrink" || 497 | clockValue == "s") 498 | { 499 | // Same as backward 500 | clockValue = "backward"; 501 | } 502 | 503 | // Set the clock parameter 504 | scaleClock.SetParameter(clockParameter, clockValue); 505 | } 506 | 507 | // Alpha related? 508 | if (parameter.substr(0, 6) == "alpha-" || 509 | parameter.substr(0, 2) == "a-") 510 | { 511 | if (debug) 512 | { 513 | outFile << "\n// Found alpha parameters"; 514 | } 515 | 516 | // Replace with clock parameter 517 | std::string clockParameter = parameter.substr((parameter.find_first_of('-') + 1)); 518 | 519 | // Replace direction convenience values with clock values 520 | std::string clockValue = value; 521 | if (clockValue == "fade-in" || 522 | clockValue == "f-i") 523 | { 524 | // Same as forward 525 | clockValue = "forward"; 526 | } 527 | else if (clockValue == "fade-out" || 528 | clockValue == "f-o") 529 | { 530 | // Same as backward 531 | clockValue = "backward"; 532 | } 533 | 534 | // Set the clock parameter 535 | alphaClock.SetParameter(clockParameter, clockValue); 536 | } 537 | 538 | // Follow orientation 539 | if (parameter == "follow-orientation" || 540 | parameter == "f-o") 541 | { 542 | if (debug) 543 | { 544 | outFile << "\n// Found follow orientation parameter"; 545 | } 546 | 547 | // Is this disabling following? 548 | if (value == "none" || 549 | value == "n") 550 | { 551 | // Disable follow 552 | this->follow = false; 553 | } 554 | else 555 | { 556 | // Enable following 557 | this->follow = true; 558 | 559 | // Parse the follow orientation "offset" in degrees 560 | this->followOrientation = (AIReal)(strtod(value.c_str(), NULL)); 561 | 562 | if (debug) 563 | { 564 | outFile << "\n// Follow orientation = " << setiosflags(ios::fixed) << setprecision(2) << 565 | this->followOrientation << " degrees"; 566 | } 567 | } 568 | } 569 | 570 | // Rasterize 571 | if (parameter == "rasterize" || 572 | parameter == "rast") 573 | { 574 | if (debug) 575 | { 576 | outFile << "\n// Found rasterize parameter"; 577 | } 578 | 579 | if (value == "no" || 580 | value == "n") 581 | { 582 | // No rasterization 583 | this->rasterizeFileName = ""; 584 | } 585 | else 586 | { 587 | // If we have a value 588 | if (!value.empty()) 589 | { 590 | std::string fileName = value; 591 | 592 | // Does the file name already have an extension? 593 | size_t index = value.find_last_of('.'); 594 | if (index != string::npos) 595 | { 596 | // Remove the extension 597 | fileName = name.substr(0, index); 598 | } 599 | 600 | // Since we'll rasterize to a PNG file, add a ".png" extension 601 | fileName += ".png"; 602 | 603 | // Store file name 604 | this->rasterizeFileName = fileName; 605 | 606 | if (debug) 607 | { 608 | outFile << "\n// Rasterize file name = " << fileName; 609 | } 610 | } 611 | } 612 | } 613 | 614 | // Crop 615 | if (parameter == "crop" || 616 | parameter == "c") 617 | { 618 | if (debug) 619 | { 620 | outFile << "\n// Found crop parameter"; 621 | } 622 | 623 | if (value == "yes" || 624 | value == "y") 625 | { 626 | // Crop 627 | this->crop = true; 628 | 629 | // Set first layer to crop 630 | // TODO: This only works on the first layer 631 | this->layers[0]->crop = true; 632 | } 633 | else if (value == "no" || 634 | value == "n") 635 | { 636 | // Don't crop 637 | this->crop = false; 638 | 639 | // Set first layer to NOT crop 640 | // TODO: This only works on the first layer 641 | this->layers[0]->crop = false; 642 | } 643 | } 644 | } 645 | 646 | bool const DrawFunction::HasAnimation() 647 | { 648 | return (this->follow || 649 | (this->rotateClock.direction != AnimationClock::kNone) || 650 | (this->scaleClock.direction != AnimationClock::kNone) || 651 | (this->alphaClock.direction != AnimationClock::kNone)); 652 | } 653 | -------------------------------------------------------------------------------- /Source/DrawFunction.h: -------------------------------------------------------------------------------- 1 | // DrawFunction.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef DRAWFUNCTION_H 24 | #define DRAWFUNCTION_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Function.h" 28 | #include "Canvas.h" 29 | #include "AnimationFunction.h" 30 | #include "Layer.h" 31 | #include "Utility.h" 32 | #include "AnimationClock.h" 33 | 34 | namespace CanvasExport 35 | { 36 | // Globals 37 | extern ofstream outFile; 38 | extern bool debug; 39 | 40 | /// Represents a JavaScript drawing function 41 | class DrawFunction : public Function 42 | { 43 | private: 44 | 45 | public: 46 | 47 | enum RotateDirection { kRotateNone, kRotateClockwise, kRotateCounterclockwise }; 48 | 49 | DrawFunction(); 50 | ~DrawFunction(); 51 | 52 | std::string requestedName; // The requested function name (not always the same as what is used) 53 | std::vector layers; // Array of layers for this drawing function 54 | bool hasGradients; // Does this function use gradients? 55 | bool hasPatterns; // Does this function use pattern fills? 56 | bool hasAlpha; // Does this function have alpha changes? 57 | AnimationFunction* animationFunction; // Associated animation function 58 | std::string animationFunctionName; // Associated animation function name (capture as string so we can late-bind after all parsing is complete) 59 | bool follow; // Does this function follow an orientation for an animation path? 60 | AIReal followOrientation; // Follow orientation (in degrees) 61 | std::string rasterizeFileName; // File name if this function is to be rasterized (empty if not) 62 | bool crop; // Crop canvas to bounds of this drawing layer? 63 | 64 | AnimationClock rotateClock; // Rotation animation clock 65 | AnimationClock scaleClock; // Scale animation clock 66 | AnimationClock alphaClock; // Alpha animation clock 67 | 68 | virtual void RenderClockInit(); // Initialize animation clocks 69 | virtual void RenderTriggerInit(); // Initialize animation clock triggers 70 | virtual void RenderClockStart(); // Start animation clocks 71 | virtual void RenderClockTick(); // Tick animation clocks 72 | virtual void SetParameter(const std::string& parameter, const std::string& value); 73 | virtual bool const HasValidTriggers(); 74 | 75 | void RenderDrawFunctionCall(const AIRealRect& documentBounds); 76 | void RenderDrawFunction(const AIRealRect& documentBounds); 77 | void Reposition(const AIRealRect& documentBounds); 78 | bool const HasAnimation(); // Does this draw function have any animation? 79 | 80 | }; 81 | } 82 | #endif 83 | -------------------------------------------------------------------------------- /Source/Function.cpp: -------------------------------------------------------------------------------- 1 | // Function.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "Function.h" 25 | 26 | using namespace CanvasExport; 27 | 28 | Function::Function() 29 | { 30 | // Initialize Function 31 | this->type = kAnyFunction; 32 | this->name = ""; 33 | this->canvas = nullptr; 34 | this->translateOrigin = false; 35 | this->translateOriginH = 0.0f; 36 | this->translateOriginV = 0.0f; 37 | 38 | // Initialize bounds 39 | // Start with absolute maximums and minimums (these will be "trimmed") 40 | this->bounds.left = FLT_MAX; 41 | this->bounds.right = -FLT_MAX; 42 | this->bounds.top = -FLT_MAX; 43 | this->bounds.bottom = FLT_MAX; 44 | } 45 | 46 | Function::~Function() 47 | { 48 | } 49 | 50 | void SetParameter(const std::string& parameter, const std::string& value) 51 | { 52 | (void)parameter; 53 | (void)value; 54 | } 55 | 56 | void Function::RenderClockInit() { } 57 | void Function::RenderTriggerInit() { } 58 | void Function::RenderClockStart() { } 59 | void Function::RenderClockTick() { } 60 | 61 | bool const Function::HasValidTriggers() { return false; } 62 | -------------------------------------------------------------------------------- /Source/Function.h: -------------------------------------------------------------------------------- 1 | // Function.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef FUNCTION_H 24 | #define FUNCTION_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Utility.h" 28 | #include "Canvas.h" 29 | 30 | namespace CanvasExport 31 | { 32 | // Represents the abstract base class for functions 33 | class Function 34 | { 35 | private: 36 | 37 | public: 38 | 39 | enum FunctionType { kAnyFunction, kDrawFunction, kAnimationFunction }; 40 | 41 | Function(); 42 | virtual ~Function(); 43 | 44 | FunctionType type; // Type of this function (not very OO, but it works) 45 | std::string name; // Name of the function 46 | Canvas* canvas; // Pointer to targeted canvas 47 | AIRealRect bounds; // Bounds of the artwork 48 | AIBoolean translateOrigin; // Do we need to translate the origin? 49 | AIReal translateOriginH; // Horizontal origin translation as a percentage 50 | AIReal translateOriginV; // Vertical origin translation as a percentage 51 | 52 | // Set function parameters 53 | virtual void SetParameter(const std::string& parameter, const std::string& value) = 0; 54 | 55 | virtual void RenderClockInit() = 0; // Initialize animation clocks 56 | virtual void RenderTriggerInit() = 0; // Initialize animation clock triggers 57 | virtual void RenderClockStart() = 0; // Start animation clocks 58 | virtual void RenderClockTick() = 0; // Tick animation clocks 59 | 60 | virtual bool const HasValidTriggers() = 0; // Does this function have any valid triggers defined? 61 | }; 62 | } 63 | #endif 64 | -------------------------------------------------------------------------------- /Source/FunctionCollection.cpp: -------------------------------------------------------------------------------- 1 | // FunctionCollection.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "FunctionCollection.h" 25 | 26 | using namespace CanvasExport; 27 | 28 | FunctionCollection::FunctionCollection() 29 | { 30 | // Initialize FunctionCollection 31 | this->animationIndex = 0; 32 | this->hasAnimationFunctions = false; 33 | this->hasDrawFunctions = false; 34 | } 35 | 36 | FunctionCollection::~FunctionCollection() 37 | { 38 | // Clear functions 39 | for (unsigned int i = 0; i < functions.size(); i++) 40 | { 41 | // Remove instance 42 | delete functions[i]; 43 | } 44 | } 45 | 46 | bool const FunctionCollection::HasAnimationFunctions() 47 | { 48 | return hasAnimationFunctions; 49 | } 50 | 51 | bool const FunctionCollection::HasDrawFunctions() 52 | { 53 | return hasDrawFunctions; 54 | } 55 | 56 | // Returns true if at least one of the draw functions includes animation 57 | bool const FunctionCollection::HasDrawFunctionAnimation() 58 | { 59 | bool hasAnimation = false; 60 | 61 | // Any draw functions to evaluate? 62 | if (hasDrawFunctions) 63 | { 64 | // Loop through functions 65 | for (unsigned int i = 0; i < functions.size(); i++) 66 | { 67 | // Draw function? 68 | if (functions[i]->type == Function::kDrawFunction) 69 | { 70 | // Any animation? 71 | if (((DrawFunction*)functions[i])->HasAnimation()) 72 | { 73 | hasAnimation = true; 74 | break; 75 | } 76 | } 77 | } 78 | } 79 | 80 | return hasAnimation; 81 | } 82 | 83 | // Initialize all animation clocks 84 | void FunctionCollection::RenderClockInit() 85 | { 86 | // Any draw function animation? 87 | if (HasDrawFunctionAnimation()) 88 | { 89 | outFile << "\n\n // Initialize animations"; 90 | 91 | // Set default draw function animation values 92 | for (unsigned int i = 0; i < functions.size(); i++) 93 | { 94 | // Draw function? 95 | if (functions[i]->type == Function::kDrawFunction) 96 | { 97 | // Render initialization for this function 98 | functions[i]->RenderClockInit(); 99 | } 100 | } 101 | } 102 | 103 | // Configure animation clock triggers 104 | // NOTE: We do this *after* all clocks have been initialized. If we don't, we have ordering problems (e.g. clocks aren't initialized yet) 105 | if (HasValidTriggers()) 106 | { 107 | outFile << "\n\n // Configure animation triggers"; 108 | 109 | // Configure function triggers 110 | for (unsigned int i = 0; i < functions.size(); i++) 111 | { 112 | // Render trigger configuration 113 | functions[i]->RenderTriggerInit(); 114 | } 115 | } 116 | } 117 | 118 | // Start all animation clocks 119 | void FunctionCollection::RenderClockStart() 120 | { 121 | // Start clocks 122 | outFile << "\n\n // Start animation clocks"; 123 | 124 | // Start animation clocks (if they have no "start" trigger defined) 125 | for (unsigned int i = 0; i < functions.size(); i++) 126 | { 127 | // Start clocks 128 | functions[i]->RenderClockStart(); 129 | } 130 | } 131 | 132 | // Tick all animation clocks 133 | void FunctionCollection::RenderClockTick() 134 | { 135 | // Any draw function animation? 136 | if (HasDrawFunctionAnimation()) 137 | { 138 | outFile << "\n\n // Update animation clocks"; 139 | outFile << "\n updateAllClocks();"; 140 | 141 | //for (unsigned int i = 0; i < functions.size(); i++) 142 | //{ 143 | // // Draw function? 144 | // if (functions[i]->type == Function::kDrawFunction) 145 | // { 146 | // // Tick animation 147 | // functions[i]->RenderClockTick(); 148 | // } 149 | //} 150 | } 151 | 152 | // If we have animation functions, include JavaScript function to update each of them 153 | if (HasAnimationFunctions()) 154 | { 155 | outFile << "\n\n // Update animation paths"; 156 | outFile << " \n var animationCount = animations.length;"; 157 | outFile << "\n for (var i = 0; i < animationCount; i++) {"; 158 | outFile << "\n animations[i].update();"; 159 | outFile << "\n }"; 160 | } 161 | } 162 | 163 | void FunctionCollection::RenderDrawFunctionCalls(const AIRealRect& documentBounds) 164 | { 165 | // Loop through all draw functions (they're already in order) 166 | for (unsigned int i = 0; i < functions.size(); i++) 167 | { 168 | // Draw function? 169 | if (functions[i]->type == Function::kDrawFunction) 170 | { 171 | // Render draw function call 172 | ((DrawFunction*)functions[i])->RenderDrawFunctionCall(documentBounds); 173 | } 174 | } 175 | } 176 | 177 | void FunctionCollection::RenderDrawFunctions(const AIRealRect& documentBounds) 178 | { 179 | // Loop through all draw functions 180 | for (unsigned int i = 0; i < functions.size(); i++) 181 | { 182 | // Draw function? 183 | if (functions[i]->type == Function::kDrawFunction) 184 | { 185 | // Render the function 186 | ((DrawFunction*)functions[i])->RenderDrawFunction(documentBounds); 187 | } 188 | } 189 | } 190 | 191 | void FunctionCollection::RenderAnimationFunctionInits(const AIRealRect& documentBounds) 192 | { 193 | // Any animations to render? 194 | if (HasAnimationFunctions()) 195 | { 196 | outFile << "\n\n // Animations"; 197 | outFile << "\n var animations = ["; 198 | 199 | // Loop through animation functions 200 | bool addComma = false; 201 | for (unsigned int i = 0; i < functions.size(); i++) 202 | { 203 | // Animation function? 204 | if (functions[i]->type == Function::kAnimationFunction) 205 | { 206 | // Do we need a comma? 207 | if (addComma) 208 | { 209 | outFile << ","; 210 | } 211 | 212 | // Add animation 213 | outFile << " new " << functions[i]->name << "()"; 214 | 215 | addComma = true; 216 | } 217 | } 218 | 219 | // Close array initialization 220 | outFile << " ];"; 221 | 222 | // Loop through animations 223 | for (unsigned int i = 0; i < functions.size(); i++) 224 | { 225 | // Animation function? 226 | if (functions[i]->type == Function::kAnimationFunction) 227 | { 228 | // Initialize 229 | ((AnimationFunction*)functions[i])->RenderInit(documentBounds); 230 | } 231 | } 232 | } 233 | } 234 | 235 | // Bind string animation function names to actual objects 236 | void FunctionCollection::BindAnimationFunctions() 237 | { 238 | // Bind animation functions names (as string) to actual animations 239 | for (unsigned int i = 0; i < functions.size(); i++) 240 | { 241 | // Draw function? 242 | if (functions[i]->type == Function::kDrawFunction) 243 | { 244 | // Convenience 245 | DrawFunction* drawFunction = (DrawFunction*)functions[i]; 246 | 247 | // Is there an animation name to resolve? 248 | if (!drawFunction->animationFunctionName.empty()) 249 | { 250 | // Resolve and assign actual animation function 251 | drawFunction->animationFunction = (AnimationFunction*)Find(drawFunction->animationFunctionName, Function::kAnimationFunction); 252 | } 253 | } 254 | } 255 | } 256 | 257 | // Bind all function triggers 258 | void FunctionCollection::BindTriggers() 259 | { 260 | // Bind all functions 261 | for (unsigned int i = 0; i < functions.size(); i++) 262 | { 263 | // Bind based on type 264 | switch (functions[i]->type) 265 | { 266 | case Function::kAnimationFunction: 267 | { 268 | // Convenience 269 | AnimationFunction* animationFunction = (AnimationFunction*)functions[i]; 270 | 271 | // Resolve triggers 272 | ResolveTriggers(animationFunction->pathClock.triggers); 273 | break; 274 | } 275 | case Function::kDrawFunction: 276 | { 277 | // Convenience 278 | DrawFunction* drawFunction = (DrawFunction*)functions[i]; 279 | 280 | // Resolve triggers 281 | ResolveTriggers(drawFunction->rotateClock.triggers); 282 | ResolveTriggers(drawFunction->scaleClock.triggers); 283 | ResolveTriggers(drawFunction->alphaClock.triggers); 284 | break; 285 | } 286 | case Function::kAnyFunction: 287 | { 288 | break; 289 | } 290 | } 291 | } 292 | } 293 | 294 | // Pass an array of triggers to be resolved (late-bound) 295 | void FunctionCollection::ResolveTriggers(std::vector& triggers) 296 | { 297 | // Loop through triggers 298 | for (unsigned int i = 0; i < triggers.size(); i++) 299 | { 300 | // Convenient reference 301 | Trigger* trigger = triggers[i]; 302 | 303 | // Try to resolve 304 | Function* function = nullptr; 305 | if (ResolveTriggerFunction(*trigger, &function)) 306 | { 307 | // Bind 308 | if (function->type == Function::kDrawFunction) 309 | { 310 | // TODO: Should this be the "used" name? 311 | trigger->sourceObject = function->name; 312 | } 313 | else if (function->type == Function::kAnimationFunction) 314 | { 315 | stringstream animation; 316 | animation << "animations[" << ((AnimationFunction*)function)->index << "]"; 317 | trigger->sourceObject = animation.str(); 318 | } 319 | trigger->parsedOkay = true; 320 | } 321 | else 322 | { 323 | // Can't bind 324 | // TODO: Should we just remove it? 325 | trigger->parsedOkay = false; 326 | } 327 | } 328 | } 329 | 330 | // Pass in a trigger, resolves function and animation clock 331 | // Returns true if successful, false if not 332 | bool FunctionCollection::ResolveTriggerFunction(Trigger& trigger, Function** function) 333 | { 334 | // Default return value 335 | bool result = false; 336 | 337 | // Is this an animation function? 338 | Function* searchFunction = nullptr; 339 | searchFunction = Find(trigger.sourceObject, Function::kAnimationFunction); 340 | 341 | // Find anything? 342 | if (searchFunction != nullptr) 343 | { 344 | // Return function 345 | *function = searchFunction; 346 | 347 | // Clock name should be empty, since there's only one clock on an animation function 348 | if (trigger.sourceClock.empty()) 349 | { 350 | // Path clock 351 | trigger.sourceClock = "pathClock"; 352 | 353 | // Note a successful resolution 354 | result = true; 355 | } 356 | } 357 | else 358 | { 359 | // Is this a draw function? 360 | bool isLast = false; 361 | searchFunction = FindDrawFunction(trigger.sourceObject, isLast); 362 | 363 | // Find anything? 364 | if (searchFunction != nullptr) 365 | { 366 | // Return function 367 | *function = searchFunction; 368 | 369 | // Resolve clock names 370 | if (trigger.sourceClock == "rotate" || 371 | trigger.sourceClock == "r") 372 | { 373 | // Rotate clock 374 | trigger.sourceClock = "rotateClock"; 375 | 376 | // Note a successful resolution 377 | result = true; 378 | } 379 | else if (trigger.sourceClock == "scale" || 380 | trigger.sourceClock == "s") 381 | { 382 | // Scale clock 383 | trigger.sourceClock = "scaleClock"; 384 | 385 | // Note a successful resolution 386 | result = true; 387 | } 388 | else if (trigger.sourceClock == "alpha" || 389 | trigger.sourceClock == "a") 390 | { 391 | // Alpha clock 392 | trigger.sourceClock = "alphaClock"; 393 | 394 | // Note a successful resolution 395 | result = true; 396 | } 397 | } 398 | } 399 | 400 | return result; 401 | } 402 | 403 | 404 | // Do the functions have any valid clock triggers? 405 | bool const FunctionCollection::HasValidTriggers() 406 | { 407 | bool result = false; 408 | 409 | for (unsigned int i = 0; i < functions.size(); i++) 410 | { 411 | if (functions[i]->HasValidTriggers()) 412 | { 413 | // Found at least one 414 | result = true; 415 | break; 416 | } 417 | } 418 | 419 | return result; 420 | } 421 | 422 | Function* FunctionCollection::Find(const std::string& name, const Function::FunctionType& functionType) 423 | { 424 | Function* function = nullptr; 425 | 426 | // Any functions to search? 427 | size_t i = functions.size(); 428 | if (i > 0) 429 | { 430 | // Loop through functions 431 | do 432 | { 433 | i--; 434 | 435 | // Correct type? 436 | if ((functions[i]->type == functionType) || 437 | (functions[i]->type == Function::kAnyFunction)) 438 | { 439 | // Do the names match? 440 | if (functions[i]->name == name) 441 | { 442 | // Found a match 443 | function = functions[i]; 444 | break; 445 | } 446 | } 447 | } while (i > 0); 448 | } 449 | 450 | // Return result 451 | return function; 452 | } 453 | 454 | // Returns a unique function name (which could be identical to what was passed in, if it's unique) 455 | std::string FunctionCollection::CreateUniqueName(const std::string& name) 456 | { 457 | // Since we may change the name, copy it first 458 | std::string usedName = name; 459 | 460 | // Does a function with this name already exist? 461 | Function* function = Find(usedName, Function::kAnyFunction); 462 | 463 | // Did we find anything? 464 | if (function) 465 | { 466 | // Find a unique name 467 | std::ostringstream uniqueName; 468 | int unique = 0; 469 | do 470 | { 471 | // Increment to make unique name 472 | unique++; 473 | 474 | // Generate a unique name 475 | uniqueName.str(""); 476 | uniqueName << usedName << unique; 477 | } while (Find(uniqueName.str(), Function::kAnyFunction)); 478 | 479 | // Assign unique name 480 | usedName = uniqueName.str(); 481 | } 482 | 483 | // Return the unique name 484 | return usedName; 485 | } 486 | 487 | // Adds a new animation function 488 | DrawFunction* FunctionCollection::AddDrawFunction(const std::string& name) 489 | { 490 | // Since we may change the name, copy it first 491 | std::string uniqueName = name; 492 | 493 | // Does a function with this name already exist? 494 | bool isLast = false; 495 | DrawFunction* drawFunction = FindDrawFunction(uniqueName, isLast); 496 | 497 | // Did we find the function? 498 | if (drawFunction) 499 | { 500 | // We found the function. Is it the most recent drawing function we've added (don't consider animation layers)? 501 | // Since drawing order is bottoms-up, we can't "go back to" a prior function and add layers to it...it must be unique at that point 502 | if (!isLast) 503 | { 504 | // It's not the most recent function, so we have to make it unique 505 | 506 | // Need a new function 507 | drawFunction = nullptr; 508 | 509 | // Generate unique name 510 | uniqueName = CreateUniqueName(uniqueName); 511 | } 512 | } 513 | else 514 | { 515 | // Matched another function type (perhaps animation), so we need a unique name 516 | uniqueName = CreateUniqueName(uniqueName); 517 | } 518 | 519 | // Do we have a function yet? 520 | if (!drawFunction) 521 | { 522 | // Create a new function 523 | drawFunction = new DrawFunction(); 524 | 525 | // Assign names 526 | drawFunction->requestedName = name; 527 | drawFunction->name = uniqueName; 528 | 529 | // Add function 530 | functions.push_back(drawFunction); 531 | 532 | // Note that we have at least one draw function in the collection 533 | hasDrawFunctions = true; 534 | } 535 | 536 | // Return the function 537 | return drawFunction; 538 | } 539 | 540 | // Find a draw function 541 | // TODO: Any way we can clean this up? Seems a bit convoluted. 542 | DrawFunction* FunctionCollection::FindDrawFunction(const std::string& name, bool& isLast) 543 | { 544 | DrawFunction* drawFunction = nullptr; 545 | 546 | // By default 547 | isLast = false; 548 | 549 | // Track if we've seen a draw function yet 550 | bool passedDrawFunction = false; 551 | 552 | // Any functions to search? 553 | size_t i = functions.size(); 554 | if (i > 0) 555 | { 556 | // Loop through functions 557 | do 558 | { 559 | i--; 560 | 561 | if (functions[i]->type == Function::kDrawFunction) 562 | { 563 | // Cast to DrawFunction 564 | DrawFunction* searchDrawFunction = (DrawFunction*)functions[i]; 565 | 566 | // Do the names match? 567 | if ((searchDrawFunction->name == name) || 568 | (searchDrawFunction->requestedName == name)) 569 | { 570 | // Found a match 571 | drawFunction = searchDrawFunction; 572 | break; 573 | } 574 | 575 | // Can't be the last, if we've made it here 576 | passedDrawFunction = true; 577 | } 578 | } while (i > 0); 579 | 580 | // Did we find something AND it's the last draw function? 581 | if (drawFunction && (!passedDrawFunction)) 582 | { 583 | isLast = true; 584 | } 585 | } 586 | 587 | // Return result 588 | return drawFunction; 589 | } 590 | 591 | // Adds a new animation function 592 | AnimationFunction* FunctionCollection::AddAnimationFunction(const std::string& name) 593 | { 594 | // Since we may change the name, copy it first 595 | std::string usedName = name; 596 | 597 | // Does a function with this name already exist? 598 | Function* function = Find(usedName, Function::kAnyFunction); 599 | 600 | // Did we find anything? 601 | if (function) 602 | { 603 | // Find a unique name 604 | std::ostringstream uniqueName; 605 | int unique = 0; 606 | do 607 | { 608 | // Increment to make unique name 609 | unique++; 610 | 611 | // Generate a unique name 612 | uniqueName.str(""); 613 | uniqueName << unique; 614 | } while (Find(uniqueName.str(), Function::kAnyFunction)); 615 | 616 | // Assign unique name 617 | usedName = uniqueName.str(); 618 | } 619 | 620 | // Now that we have a unique name, create a new animation function 621 | AnimationFunction* animationFunction = new AnimationFunction(); 622 | 623 | // Assign properties 624 | animationFunction->name = usedName; 625 | animationFunction->index = animationIndex; 626 | 627 | // Increment index 628 | animationIndex++; 629 | 630 | // Add it to the functions array 631 | functions.push_back(animationFunction); 632 | 633 | // Note that we have at least one animation function in the collection 634 | hasAnimationFunctions = true; 635 | 636 | // Return new animation function 637 | return animationFunction; 638 | } 639 | 640 | void FunctionCollection::DebugInfo() 641 | { 642 | // Gather info 643 | unsigned int drawFunctionCount = 0; 644 | unsigned int animationFunctionCount = 0; 645 | 646 | // Loop through functions 647 | for (unsigned int i = 0; i < functions.size(); i++) 648 | { 649 | switch (functions[i]->type) 650 | { 651 | case Function::kAnimationFunction: 652 | { 653 | ++animationFunctionCount; 654 | break; 655 | } 656 | case Function::kDrawFunction: 657 | { 658 | ++drawFunctionCount; 659 | break; 660 | } 661 | case Function::kAnyFunction: 662 | { 663 | break; 664 | } 665 | } 666 | } 667 | 668 | // Animation function debug info 669 | outFile << "\n

Animation functions: " << animationFunctionCount << "

"; 670 | 671 | // Anything to list? 672 | if (animationFunctionCount > 0) 673 | { 674 | // Start unordered list 675 | outFile << "\n
    "; 676 | 677 | // Loop through each animation function 678 | for (unsigned int i = 0; i < functions.size(); i++) 679 | { 680 | if (functions[i]->type == Function::kAnimationFunction) 681 | { 682 | // For convenience 683 | AnimationFunction* animationFunction = (AnimationFunction*)functions[i]; 684 | 685 | outFile << "\n
  • name: " << animationFunction->name << ", index: " << animationFunction->index << 686 | ", segments: " << animationFunction->beziers.size() << 687 | ", linear segment length: " << setiosflags(ios::fixed) << setprecision(1) << animationFunction->segmentLength << "
  • "; 688 | } 689 | } 690 | 691 | // End unordered list 692 | outFile << "\n
"; 693 | } 694 | 695 | // Draw function debug info 696 | outFile << "\n

Draw functions: " << drawFunctionCount << "

"; 697 | 698 | // Anything to list? 699 | if (drawFunctionCount > 0) 700 | { 701 | // Start unordered list 702 | outFile << "\n
    "; 703 | 704 | // Loop through each draw function 705 | for (unsigned int i = 0; i < functions.size(); i++) 706 | { 707 | if (functions[i]->type == Function::kDrawFunction) 708 | { 709 | // For convenience 710 | DrawFunction* drawFunction = (DrawFunction*)functions[i]; 711 | 712 | outFile << "\n
  • name: " << drawFunction->name << ", layers: " << drawFunction->layers.size() << "
  • "; 713 | } 714 | } 715 | 716 | // End unordered list 717 | outFile << "\n
"; 718 | } 719 | } 720 | -------------------------------------------------------------------------------- /Source/FunctionCollection.h: -------------------------------------------------------------------------------- 1 | // FunctionCollection.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef FUNCTIONCOLLECTION_H 24 | #define FUNCTIONCOLLECTION_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Function.h" 28 | #include "AnimationFunction.h" 29 | #include "DrawFunction.h" 30 | #include "Utility.h" 31 | 32 | namespace CanvasExport 33 | { 34 | // Globals 35 | extern ofstream outFile; 36 | extern bool debug; 37 | 38 | /// Represents a collection of functions 39 | class FunctionCollection 40 | { 41 | private: 42 | 43 | unsigned int animationIndex; // Track JavaScript array index for animation functions 44 | bool hasAnimationFunctions; // Does the collection include at least one animation function? 45 | bool hasDrawFunctions; // Does the collection include at least one draw function? 46 | 47 | public: 48 | 49 | FunctionCollection(); 50 | ~FunctionCollection(); 51 | 52 | std::vector functions; // Collection of functions 53 | 54 | bool const HasAnimationFunctions(); 55 | bool const HasDrawFunctions(); 56 | bool const HasDrawFunctionAnimation(); 57 | Function* Find(const std::string& name, const Function::FunctionType& functionType); 58 | std::string CreateUniqueName(const std::string& name); 59 | DrawFunction* AddDrawFunction(const std::string& name); 60 | DrawFunction* FindDrawFunction(const std::string& name, bool& isLast); 61 | AnimationFunction* AddAnimationFunction(const std::string& name); 62 | bool const HasValidTriggers(); 63 | 64 | void RenderClockInit(); 65 | void RenderClockStart(); 66 | void RenderClockTick(); 67 | void RenderDrawFunctionCalls(const AIRealRect& documentBounds); 68 | void RenderDrawFunctions(const AIRealRect& documentBounds); 69 | void RenderAnimationFunctionInits(const AIRealRect& documentBounds); 70 | 71 | void BindAnimationFunctions(); 72 | void BindTriggers(); 73 | void ResolveTriggers(std::vector& triggers); 74 | bool ResolveTriggerFunction(Trigger& trigger, Function** function); 75 | void DebugInfo(); 76 | 77 | }; 78 | } 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /Source/Image.cpp: -------------------------------------------------------------------------------- 1 | // Image.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "Image.h" 25 | 26 | using namespace CanvasExport; 27 | 28 | Image::Image(const std::string& id, const std::string& path) 29 | { 30 | // Initialize Image 31 | this->id = id; 32 | this->path = path; 33 | this->name = ""; 34 | this->pathIsAbsolute = false; 35 | } 36 | 37 | Image::~Image() 38 | { 39 | } 40 | 41 | void Image::Render() 42 | { 43 | // Output image tag 44 | outFile << "\n \"""; 45 | } 46 | 47 | std::string Image::Uri() 48 | { 49 | // Create file URI 50 | ai::UnicodeString usPath(path); 51 | ai::FilePath aiFilePath(usPath); 52 | std::string uri = aiFilePath.GetAsURL(false).as_Platform(); 53 | 54 | // Firefox doesn't like local "file:" references 55 | if (!pathIsAbsolute && uri.length() >= 5 && uri.substr(0, 5) == "file:") 56 | { 57 | // Strip "file:" from string 58 | uri = uri.substr(5); 59 | } 60 | 61 | // Initial slashes? 62 | if (!pathIsAbsolute && uri.length() >= 3 && uri.substr(0, 3) == "///") 63 | { 64 | // Strip "///" from string 65 | uri = uri.substr(3); 66 | } 67 | 68 | return uri; 69 | } 70 | 71 | void Image::RenderDrawImage(const std::string& contextName, const AIReal x, const AIReal y) 72 | { 73 | // Draw image 74 | outFile << "\n" << Indent(0) << contextName << ".drawImage(document.getElementById(\"" << id << "\"), " << 75 | setiosflags(ios::fixed) << setprecision(1) << 76 | x << ", " << y << ");"; 77 | } 78 | 79 | void Image::DebugBounds(const std::string& contextName, const AIRealRect& bounds) 80 | { 81 | if (debug) 82 | { 83 | // Stroke bounds 84 | outFile << "\n" << Indent(0) << contextName << ".save();"; 85 | outFile << "\n" << Indent(0) << contextName << ".lineWidth = 1.0;"; 86 | outFile << "\n" << Indent(0) << contextName << ".strokeStyle = \"rgb(255, 0, 0)\";"; 87 | outFile << "\n" << Indent(0) << contextName << ".strokeRect(" << 88 | setiosflags(ios::fixed) << setprecision(1) << 89 | bounds.left << ", " << bounds.top << ", " << (bounds.right - bounds.left) << ", " << (bounds.bottom - bounds.top) << ");"; 90 | outFile << "\n" << Indent(0) << contextName << ".restore();"; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Source/Image.h: -------------------------------------------------------------------------------- 1 | // Image.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef IMAGE_H 24 | #define IMAGE_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Utility.h" 28 | 29 | namespace CanvasExport 30 | { 31 | // Globals 32 | extern ofstream outFile; 33 | extern bool debug; 34 | 35 | /// Represents a bitmap image 36 | class Image 37 | { 38 | private: 39 | 40 | 41 | public: 42 | 43 | Image(const std::string& id, const std::string& path); 44 | ~Image(); 45 | 46 | std::string id; // Image element ID 47 | std::string path; // File path to the image 48 | std::string name; // Name of the image (to be used for the alt attribute) 49 | bool pathIsAbsolute; // Is this an absolute image path? 50 | 51 | void Render(); 52 | void RenderDrawImage(const std::string& contextName, const AIReal x, const AIReal y); 53 | void DebugBounds(const std::string& contextName, const AIRealRect& bounds); 54 | std::string Uri(); 55 | 56 | }; 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /Source/ImageCollection.cpp: -------------------------------------------------------------------------------- 1 | // ImageCollection.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "ImageCollection.h" 25 | 26 | using namespace CanvasExport; 27 | 28 | ImageCollection::ImageCollection() 29 | { 30 | } 31 | 32 | ImageCollection::~ImageCollection() 33 | { 34 | // Clear images 35 | for (unsigned int i = 0; i < images.size(); i++) 36 | { 37 | // Remove instance 38 | delete images[i]; 39 | } 40 | } 41 | 42 | void ImageCollection::Render() 43 | { 44 | // Render images 45 | for (unsigned int i = 0; i < images.size(); i++) 46 | { 47 | // Render 48 | images[i]->Render(); 49 | } 50 | } 51 | 52 | // Won't add an image if it already exists 53 | Image* ImageCollection::Add(const std::string& path) 54 | { 55 | // Does this image already exist? 56 | Image* image = Find(path); 57 | 58 | // Did we find anything? 59 | if (!image) 60 | { 61 | // Create image ID 62 | std::ostringstream id; 63 | id << "image" << (images.size() + 1); 64 | 65 | // Create a new image 66 | image = new Image(id.str(), path); 67 | 68 | // Add to document 69 | images.push_back(image); 70 | } 71 | 72 | // Return result 73 | return image; 74 | } 75 | 76 | // Find an image, returns NULL if not found 77 | Image* ImageCollection::Find(const std::string& path) 78 | { 79 | Image* result = nullptr; 80 | 81 | // Loop through images 82 | for (unsigned int i = 0; i < images.size(); i++) 83 | { 84 | // Do the paths match? 85 | if (images[i]->path == path) 86 | { 87 | // Found a match 88 | result = images[i]; 89 | break; 90 | } 91 | } 92 | 93 | // Return result 94 | return result; 95 | } 96 | 97 | void ImageCollection::DebugInfo() 98 | { 99 | // Image debug info 100 | outFile << "\n

Bitmap images: " << images.size() << "

"; 101 | 102 | // Anything to list? 103 | if (images.size() > 0) 104 | { 105 | // Start unordered list 106 | outFile << "\n
    "; 107 | 108 | // Loop through each image 109 | for (unsigned int i = 0; i < images.size(); i++) 110 | { 111 | outFile << "\n
  • ID: " << images[i]->id << 112 | ", path: Uri() << "\" target=\"_blank\">" << images[i]->path << "
  • "; 113 | } 114 | 115 | // End unordered list 116 | outFile << "\n
"; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /Source/ImageCollection.h: -------------------------------------------------------------------------------- 1 | // ImageCollection.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef IMAGECOLLECTION_H 24 | #define IMAGECOLLECTION_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Image.h" 28 | #include "Utility.h" 29 | 30 | namespace CanvasExport 31 | { 32 | // Globals 33 | extern ofstream outFile; 34 | extern bool debug; 35 | 36 | /// Represents a collection of images 37 | class ImageCollection 38 | { 39 | private: 40 | 41 | std::vector images; // Collection of image pointers 42 | 43 | public: 44 | 45 | ImageCollection(); 46 | ~ImageCollection(); 47 | 48 | void Render(); 49 | Image* Add(const std::string& path); 50 | Image* Find(const std::string& path); 51 | void DebugInfo(); 52 | 53 | }; 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /Source/Layer.cpp: -------------------------------------------------------------------------------- 1 | // Layer.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "Ai2CanvasSuites.h" 25 | #include "Layer.h" 26 | 27 | using namespace CanvasExport; 28 | 29 | Layer::Layer() 30 | { 31 | // Initialize Layer 32 | this->name = ""; 33 | this->layerHandle = nullptr; 34 | this->artHandle = nullptr; 35 | this->hasGradients = false; 36 | this->hasPatterns = false; 37 | this->hasAlpha = false; 38 | this->crop = false; 39 | 40 | // Initialize bounds 41 | // Start with absolute maximums and minimums (these will be "trimmed") 42 | this->bounds.left = FLT_MAX; 43 | this->bounds.right = -FLT_MAX; 44 | this->bounds.top = -FLT_MAX; 45 | this->bounds.bottom = FLT_MAX; 46 | } 47 | 48 | Layer::~Layer() 49 | { 50 | } 51 | 52 | // ******************** GLOBAL FUNCTIONS ******************** 53 | 54 | // Add a new layer 55 | Layer* CanvasExport::AddLayer(std::vector& layers, const AILayerHandle& layerHandle) 56 | { 57 | // Get layer name 58 | ai::UnicodeString layerName; 59 | sAILayer->GetLayerTitle(layerHandle, layerName); 60 | if (debug) 61 | { 62 | outFile << "\n// Layer name = " << layerName.as_Platform(); 63 | } 64 | 65 | // Create a new layer 66 | Layer* layer = new Layer(); 67 | 68 | // Set values 69 | layer->layerHandle = layerHandle; 70 | layer->name = layerName.as_Platform(); 71 | 72 | // Add to document 73 | layers.push_back(layer); 74 | 75 | // Return result 76 | return layer; 77 | } 78 | -------------------------------------------------------------------------------- /Source/Layer.h: -------------------------------------------------------------------------------- 1 | // Layer.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef LAYER_H 24 | #define LAYER_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Utility.h" 28 | 29 | namespace CanvasExport 30 | { 31 | // Globals 32 | extern ofstream outFile; 33 | extern bool debug; 34 | 35 | /// Represents a layer 36 | class Layer 37 | { 38 | private: 39 | 40 | public: 41 | 42 | Layer(); 43 | ~Layer(); 44 | 45 | std::string name; // Name of this layer 46 | AILayerHandle layerHandle; // Illustrator layer handle 47 | AIArtHandle artHandle; // First art in this layer 48 | AIRealRect bounds; // Bounds of the visible elements in this layer 49 | bool hasGradients; // Does this layer use gradients? 50 | bool hasPatterns; // Does this layer use pattern fills? 51 | bool hasAlpha; // Does this layer use alpha? 52 | bool crop; // Crop canvas to the bounds of this layer? 53 | }; 54 | 55 | // Global functions 56 | Layer* AddLayer(std::vector& layers, const AILayerHandle& layerHandle); 57 | } 58 | #endif 59 | -------------------------------------------------------------------------------- /Source/Pattern.cpp: -------------------------------------------------------------------------------- 1 | // Pattern.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "Pattern.h" 25 | 26 | using namespace CanvasExport; 27 | 28 | // Unsure why Xcode requires the explicit namespace before the constructor 29 | CanvasExport::Pattern::Pattern() 30 | { 31 | // Initialize Pattern 32 | this->name = ""; 33 | this->patternHandle = nullptr; 34 | this->canvasIndex = -1; 35 | this->isSymbol = false; 36 | this->hasGradients = false; 37 | this->hasPatterns = false; 38 | this->hasAlpha = false; 39 | } 40 | 41 | // Unsure why Xcode requires the explicit namespace before the destructor 42 | CanvasExport::Pattern::~Pattern() 43 | { 44 | } 45 | -------------------------------------------------------------------------------- /Source/Pattern.h: -------------------------------------------------------------------------------- 1 | // Pattern.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef PATTERN_H 24 | #define PATTERN_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Utility.h" 28 | 29 | namespace CanvasExport 30 | { 31 | // Globals 32 | extern ofstream outFile; 33 | extern bool debug; 34 | 35 | /// Represents a pattern 36 | class Pattern 37 | { 38 | private: 39 | 40 | public: 41 | 42 | Pattern(); 43 | ~Pattern(); 44 | 45 | std::string name; // Name of the pattern/symbol 46 | AIPatternHandle patternHandle; // Handle to the pattern (for matching with artwork) 47 | int canvasIndex; // Index number for canvas 48 | bool isSymbol; // Is this pattern an Illustrator symbol? 49 | bool hasGradients; // Does this pattern use gradients? 50 | bool hasPatterns; // Does this pattern use pattern fills? 51 | bool hasAlpha; // Does this pattern use alpha? 52 | 53 | }; 54 | } 55 | #endif 56 | -------------------------------------------------------------------------------- /Source/PatternCollection.cpp: -------------------------------------------------------------------------------- 1 | // PatternCollection.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "PatternCollection.h" 25 | 26 | using namespace CanvasExport; 27 | 28 | PatternCollection::PatternCollection() 29 | { 30 | // Initialize PatternCollection 31 | this->hasPatterns = false; 32 | this->hasSymbols = false; 33 | this->canvasIndex = 0; 34 | } 35 | 36 | PatternCollection::~PatternCollection() 37 | { 38 | // Clear patterns 39 | for (unsigned int i = 0; i < patterns.size(); i++) 40 | { 41 | // Remove instance 42 | delete patterns[i]; 43 | } 44 | } 45 | 46 | std::vector& PatternCollection::Patterns() 47 | { 48 | return patterns; 49 | } 50 | 51 | bool PatternCollection::HasPatterns() 52 | { 53 | return hasPatterns; 54 | } 55 | 56 | bool PatternCollection::HasSymbols() 57 | { 58 | return hasSymbols; 59 | } 60 | 61 | // TODO: Should only add a new pattern if there is no existing pattern 62 | // Returns true if a new pattern was added, or false if it already exists 63 | bool PatternCollection::Add(AIPatternHandle patternHandle, bool isSymbol) 64 | { 65 | // Track whether or not this pattern exists 66 | bool patternExists = (Find(patternHandle) != nullptr); 67 | 68 | // Does it already exist? 69 | if (!patternExists) 70 | { 71 | // Create a new pattern 72 | Pattern* pattern = new Pattern(); 73 | 74 | // Initialize default pattern values 75 | pattern->patternHandle = patternHandle; 76 | pattern->isSymbol = isSymbol; 77 | 78 | // If this is a pattern, track canvas index 79 | if (!isSymbol) 80 | { 81 | canvasIndex++; 82 | pattern->canvasIndex = canvasIndex; 83 | } 84 | 85 | // Get pattern name 86 | // TODO: Do we need to make this unique? Does Illustrator allow duplicates? 87 | ai::UnicodeString patternName; 88 | sAIPattern->GetPatternName(pattern->patternHandle, patternName); 89 | std::string name = patternName.as_Platform(); 90 | CleanString(name, true); 91 | pattern->name = name; 92 | 93 | // Add to vector 94 | patterns.push_back(pattern); 95 | 96 | // Track this collection 97 | this->hasPatterns |= (!isSymbol); 98 | this->hasSymbols |= isSymbol; 99 | } 100 | 101 | return !patternExists; 102 | } 103 | 104 | // Find a pattern, returns NULL if not found 105 | CanvasExport::Pattern* PatternCollection::Find(AIPatternHandle patternHandle) 106 | { 107 | Pattern* result = nullptr; 108 | 109 | // Loop through patterns 110 | for (unsigned int i = 0; i < patterns.size(); i++) 111 | { 112 | // Do the handles match? 113 | if (patterns[i]->patternHandle == patternHandle) 114 | { 115 | // Found a match 116 | result = patterns[i]; 117 | break; 118 | } 119 | } 120 | 121 | // Return result 122 | return result; 123 | } 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /Source/PatternCollection.h: -------------------------------------------------------------------------------- 1 | // PatternCollection.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef PATTERNCOLLECTION_H 24 | #define PATTERNCOLLECTION_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Ai2CanvasSuites.h" 28 | #include "Pattern.h" 29 | #include "Utility.h" 30 | 31 | namespace CanvasExport 32 | { 33 | // Globals 34 | extern ofstream outFile; 35 | extern bool debug; 36 | 37 | /// Represents a collection of patterns (which includes symbols) 38 | class PatternCollection 39 | { 40 | private: 41 | 42 | std::vector patterns; // Collection of patterns 43 | bool hasPatterns; // Does the collection include at least one pattern? 44 | bool hasSymbols; // Does the collection include at least one symbol? 45 | unsigned int canvasIndex; // Track next available canvas index 46 | 47 | public: 48 | 49 | PatternCollection(); 50 | ~PatternCollection(); 51 | 52 | bool Add(AIPatternHandle patternHandle, bool isSymbol); 53 | Pattern* Find(AIPatternHandle patternHandle); 54 | std::vector& Patterns(); 55 | bool HasPatterns(); 56 | bool HasSymbols(); 57 | }; 58 | } 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /Source/State.cpp: -------------------------------------------------------------------------------- 1 | // State.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "State.h" 25 | 26 | using namespace CanvasExport; 27 | 28 | State::State() 29 | { 30 | // Default color string 31 | const std::string defaultColor("\"rgb(0, 0, 0)\""); 32 | 33 | // Initialize State 34 | // NOTE: These are the HTML5 canvas defaults: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#2dcontext 35 | this->globalAlpha = 1.0f; 36 | this->fillStyle = defaultColor; 37 | this->strokeStyle = defaultColor; 38 | this->lineWidth = 1.0f; 39 | this->lineCap = kAIButtCap; 40 | this->lineJoin = kAIMiterJoin; 41 | this->miterLimit = 10.0f; 42 | this->fontSize = 10.0f; 43 | this->fontName = "sans-serif"; 44 | this->fontStyleName = "Regular"; 45 | this->isProcessingSymbol = false; 46 | sAIRealMath->AIRealMatrixSetIdentity(&this->internalTransform); 47 | } 48 | 49 | State::~State() 50 | { 51 | } 52 | 53 | // Report state information 54 | void State::DebugInfo() 55 | { 56 | outFile << "\n\n// State Info"; 57 | outFile << "\n// globalAlpha = " << setiosflags(ios::fixed) << setprecision(2) << this->globalAlpha; 58 | outFile << "\n// fillStyle = " << this->fillStyle; 59 | outFile << "\n// strokeStyle = " << this->strokeStyle; 60 | outFile << "\n// lineWidth = " << setiosflags(ios::fixed) << setprecision(1) << this->lineWidth; 61 | outFile << "\n// lineCap = " << this->lineCap; 62 | outFile << "\n// lineJoin = " << this->lineJoin; 63 | outFile << "\n// miterLimit = " << setiosflags(ios::fixed) << setprecision(1) << this->miterLimit; 64 | outFile << "\n// fontSize = " << setiosflags(ios::fixed) << setprecision(1) << this->fontSize; 65 | outFile << "\n// fontName = " << this->fontName; 66 | outFile << "\n// fontStyleName = " << this->fontStyleName; 67 | outFile << "\n// isProcessingSymbol = " << this->isProcessingSymbol; 68 | outFile << "\n// internalTransform = "; 69 | //RenderTransform(state.internalTransform); 70 | } 71 | -------------------------------------------------------------------------------- /Source/State.h: -------------------------------------------------------------------------------- 1 | // State.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef STATE_H 24 | #define STATE_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Utility.h" 28 | 29 | namespace CanvasExport 30 | { 31 | // Globals 32 | extern ofstream outFile; 33 | extern bool debug; 34 | 35 | /// Represents a context drawing state 36 | class State 37 | { 38 | private: 39 | 40 | public: 41 | 42 | State(); 43 | ~State(); 44 | 45 | AIReal globalAlpha; // Global canvas alpha value (0.0 - 1.0) 46 | std::string fillStyle; // String fill style (e.g. "rgb(0, 0, 0)") 47 | std::string strokeStyle; // String stroke style (e.g. "rgb(0, 0, 0)") 48 | AIReal lineWidth; // Stroke width (in pixels) 49 | AILineCap lineCap; // Cap type 50 | AILineJoin lineJoin; // Join type 51 | AIReal miterLimit; // Stroke miter limit 52 | AIReal fontSize; // Font size (in pixels) 53 | std::string fontName; // Font name 54 | std::string fontStyleName; // Style name 55 | AIBoolean isProcessingSymbol; // Is an Illustrator symbol being processed? 56 | AIRealMatrix internalTransform; // Internal transformation for adjustments from Illustrator to canvas coordinate space 57 | 58 | void DebugInfo(); 59 | }; 60 | 61 | } 62 | #endif 63 | -------------------------------------------------------------------------------- /Source/Trigger.cpp: -------------------------------------------------------------------------------- 1 | // Trigger.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "Trigger.h" 25 | 26 | using namespace CanvasExport; 27 | 28 | Trigger::Trigger() 29 | { 30 | // Initialize Trigger 31 | this->parsedOkay = false; 32 | this->sourceObject = ""; 33 | this->sourceClock = ""; 34 | this->sourceEvent = ""; 35 | this->triggeredFunction = ""; 36 | } 37 | 38 | Trigger::~Trigger() 39 | { 40 | } 41 | 42 | void Trigger::SetParameter(const std::string& parameter, const std::string& value) 43 | { 44 | std::string parameterName = parameter; 45 | 46 | // Need to modify any "short-cuts"? 47 | if (parameterName == "fast-forward") 48 | { 49 | // Change to correct JavaScript function name 50 | parameterName = "fastForward"; 51 | } 52 | 53 | // Parameter should be the name of the trigger 54 | this->triggeredFunction = parameterName; 55 | 56 | // Parse value into object-clock-event 57 | // Store as strings for now, since they'll have to be bound after everything has been parsed 58 | 59 | // Tokenize the values 60 | std::vector values = Tokenize(value, "-"); 61 | 62 | // Process based on whether we have 2 or 3 values 63 | switch (values.size()) 64 | { 65 | case 2: 66 | { 67 | // Is this a valid event? 68 | if (IsValidEvent(values[1])) 69 | { 70 | // object-event (object has a single clock...like an animation path function) 71 | this->sourceObject = values[0]; 72 | this->sourceClock = ""; 73 | this->sourceEvent = values[1]; 74 | 75 | // Note that we parsed 76 | this->parsedOkay = true; 77 | } 78 | 79 | break; 80 | } 81 | case 3: 82 | { 83 | // Is this a valid event? 84 | if (IsValidEvent(values[2])) 85 | { 86 | // object-clock-event (object has multiple clocks...like a draw function) 87 | this->sourceObject = values[0]; 88 | this->sourceClock = values[1]; 89 | this->sourceEvent = values[2]; 90 | 91 | // Note that we parsed 92 | this->parsedOkay = true; 93 | } 94 | 95 | break; 96 | } 97 | } 98 | 99 | if (debug) 100 | { 101 | outFile << "\n// triggeredFunction = " << this->triggeredFunction; 102 | outFile << "\n// sourceObject = " << this->sourceObject; 103 | outFile << "\n// sourceClock = " << this->sourceClock; 104 | outFile << "\n// sourceEvent = " << this->sourceEvent; 105 | } 106 | } 107 | 108 | // Is the value a valid event name? 109 | bool Trigger::IsValidEvent(const std::string& value) 110 | { 111 | return (value == "started" || 112 | value == "stopped" || 113 | value == "iterated" || 114 | value == "finished"); 115 | } 116 | 117 | void Trigger::JSTriggerInit(const std::string& objectName, const std::string& clockName) 118 | { 119 | if (this->parsedOkay) 120 | { 121 | // Output JavaScript initialization 122 | // animations[0].pathClock.finished.subscribe(function() { animations[0].pathClock.reset(); }); 123 | outFile << "\n " << this->sourceObject << 124 | "." << this->sourceClock << 125 | "." << this->sourceEvent << ".subscribe(function() { " << 126 | objectName << "." << 127 | clockName << "." << 128 | this->triggeredFunction << "(); });"; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /Source/Trigger.h: -------------------------------------------------------------------------------- 1 | // Trigger.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef TRIGGER_H 24 | #define TRIGGER_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Utility.h" 28 | 29 | namespace CanvasExport 30 | { 31 | // Globals 32 | extern ofstream outFile; 33 | extern bool debug; 34 | 35 | // Represents an animation trigger 36 | class Trigger 37 | { 38 | private: 39 | 40 | public: 41 | 42 | Trigger(); 43 | ~Trigger(); 44 | 45 | bool parsedOkay; // Did the parse complete okay? 46 | std::string sourceObject; // Name of the source object 47 | std::string sourceClock; // Name of the source animation clock 48 | std::string sourceEvent; // Name of the source event 49 | std::string triggeredFunction; // Name of the triggered function 50 | 51 | void SetParameter(const std::string& parameter, const std::string& value); 52 | bool IsValidEvent(const std::string& value); 53 | void JSTriggerInit(const std::string& objectName, const std::string& clockName); 54 | }; 55 | } 56 | #endif 57 | -------------------------------------------------------------------------------- /Source/Utility.cpp: -------------------------------------------------------------------------------- 1 | // Utility.cpp 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #include "IllustratorSDK.h" 24 | #include "Utility.h" 25 | 26 | using namespace CanvasExport; 27 | 28 | // TODO: Consider something more like: fprintf(m_fp, "\n%*sIndented by 2", 2, ""); 29 | // Or std::string(indent, ' ') 30 | std::string CanvasExport::Indent(size_t depth) 31 | { 32 | if (debug) 33 | { 34 | return std::string((depth * 2), ' '); 35 | } 36 | else 37 | { 38 | return " "; 39 | } 40 | } 41 | 42 | bool CanvasExport::OpenFile(const std::string& filePath) 43 | { 44 | // Open the file 45 | outFile.open(filePath.c_str(), ios::out); 46 | 47 | // Return result 48 | return outFile.is_open(); 49 | } 50 | 51 | void CanvasExport::CloseFile() 52 | { 53 | // Close the file 54 | outFile.close(); 55 | } 56 | 57 | void CanvasExport::RenderTransform(const AIRealMatrix& matrix) 58 | { 59 | // Transform 60 | outFile << setiosflags(ios::fixed) << setprecision(3) << 61 | matrix.a << ", " << matrix.b << ", " << matrix.c << ", " << matrix.d << ", " << 62 | setprecision(1) << 63 | matrix.tx << ", " << matrix.ty; 64 | } 65 | 66 | // In-place replacement of one character for another 67 | void CanvasExport::Replace(std::string& s, char find, char replace) 68 | { 69 | // Loop through string 70 | for (unsigned int i = 0; i < s.length(); i++) 71 | { 72 | // Does this character match? 73 | if (s[i] == find) 74 | { 75 | // Replace the character 76 | s[i] = replace; 77 | } 78 | } 79 | } 80 | 81 | // Removes spaces and other invalid characters from the string 82 | // camelCase == true, converts string to camel case 83 | // TODO: Should we allow dashes and periods here? Or use a separate function to clean those? 84 | void CanvasExport::CleanString(std::string& s, AIBoolean camelCase) 85 | { 86 | int destIndex = 0; 87 | AIBoolean newWord = true; // Are we processing a new word? 88 | AIBoolean firstLetter = true; // Are we looking for the first letter (so we can make lower-case)? 89 | 90 | // Loop through the whole string 91 | for (unsigned int i = 0; i < s.length(); i++) 92 | { 93 | // Is this a valid character? 94 | if ((s[i] >= '0' && s[i] <= '9') || 95 | (s[i] >= 'A' && s[i] <= 'Z') || 96 | (s[i] >= 'a' && s[i] <= 'z') || 97 | (s[i] == ' ')) 98 | { 99 | // If we're doing camel casing 100 | if (camelCase) 101 | { 102 | // Do we need to watch for a new word? 103 | if (s[i] == ' ') 104 | { 105 | // Watching for new word 106 | newWord = true; 107 | } 108 | else 109 | { 110 | // Are we watching for a new word? 111 | if (newWord) 112 | { 113 | // Have we processed the first letter yet? 114 | if (firstLetter) 115 | { 116 | // Is the first letter upper-case? 117 | if (s[i] >= 'A' && s[i] <= 'Z') 118 | { 119 | // Make lower-case 120 | s[i] += 32; 121 | } 122 | 123 | // No longer watching for the first letter 124 | firstLetter = false; 125 | } 126 | else 127 | { 128 | // Do we have a lower-case letter we need to make upper-case? 129 | if (s[i] >= 'a' && s[i] <= 'z') 130 | { 131 | // Make upper-case 132 | s[i] -= 32; 133 | } 134 | } 135 | 136 | // No longer watching for a new word 137 | newWord = false; 138 | } 139 | } 140 | } 141 | 142 | // If we don't have a space or we're not doing camel casing 143 | if (s[i] != ' ' || !camelCase) 144 | { 145 | // Copy the character 146 | s[destIndex] = s[i]; 147 | 148 | // Move destination index to next character 149 | destIndex++; 150 | } 151 | } 152 | } 153 | 154 | // Remove any remaining characters 155 | s.erase(destIndex); 156 | } 157 | 158 | // If they exist, removes parenthesis and parameters from a function name 159 | void CanvasExport::CleanFunction(std::string& s) 160 | { 161 | size_t length = s.length(); 162 | if (length > 3) 163 | { 164 | // Does the end of the string contain function syntax? 165 | if (s.substr(length - 2) == ");") 166 | { 167 | // Find the opening parenthesis 168 | size_t index = s.find_last_of('('); 169 | 170 | // Did we find the parenthesis? 171 | if (index != string::npos) 172 | { 173 | // Terminate the name starting at the opening parenthesis 174 | s.erase(index); 175 | } 176 | } 177 | } 178 | } 179 | 180 | // Cleans a function parameter value 181 | void CanvasExport::CleanParameter(std::string& s) 182 | { 183 | int destIndex = 0; 184 | 185 | // Loop through the whole string 186 | for (unsigned int i = 0; i < s.length(); i++) 187 | { 188 | // Is this a valid character? 189 | if ((s[i] >= '0' && s[i] <= '9') || 190 | (s[i] >= 'A' && s[i] <= 'Z') || 191 | (s[i] >= 'a' && s[i] <= 'z') || 192 | (s[i] == '-') || 193 | (s[i] == '.') || 194 | (s[i] == ',')) 195 | { 196 | // Copy the character 197 | s[destIndex] = s[i]; 198 | 199 | // Move destination index to next character 200 | destIndex++; 201 | } 202 | } 203 | 204 | // Remove any remaining characters 205 | s.erase(destIndex); 206 | } 207 | 208 | // Turn a string into a valid HTML ID 209 | // HTML5 ID draft spec: http://dev.w3.org/html5/spec/elements.html#the-id-attribute 210 | // Note that most references recommend using A-Z, a-z, 0-9, and should begin with an alpha character 211 | // Technically, hyphens ("-"), underscores ("_"), colons (":"), and periods (".") are allowed, but they're known to cause issues with things like jQuery 212 | void CanvasExport::MakeValidID(std::string& s) 213 | { 214 | // First, clean the string so that it only contains camel-cased alpha-numeric data 215 | CleanString(s, true); 216 | 217 | // Check to see if the first character is numeric 218 | if (s[0] >= '0' && s[0] <= '9') 219 | { 220 | // String starts with a number, so arbitrarily prepend an 'a' 221 | s.insert(0, "a"); 222 | } 223 | } 224 | 225 | void CanvasExport::ToLower(std::string& s) 226 | { 227 | // Loop through the whole string 228 | for (unsigned int i = 0; i < s.length(); i++) 229 | { 230 | // Is the letter upper-case? 231 | if (s[i] >= 'A' && s[i] <= 'Z') 232 | { 233 | // Make lower-case 234 | s[i] += 32; 235 | } 236 | } 237 | } 238 | 239 | // Handy tokenize function 240 | vector CanvasExport::Tokenize(const std::string& str, const std::string& delimiters) 241 | { 242 | std::vector tokens; 243 | 244 | // skip delimiters at beginning. 245 | std::string::size_type lastPos = str.find_first_not_of(delimiters, 0); 246 | 247 | // find first "non-delimiter". 248 | std::string::size_type pos = str.find_first_of(delimiters, lastPos); 249 | 250 | while (std::string::npos != pos || std::string::npos != lastPos) 251 | { 252 | // found a token, add it to the vector. 253 | tokens.push_back(str.substr(lastPos, pos - lastPos)); 254 | 255 | // skip delimiters. Note the "not_of" 256 | lastPos = str.find_first_not_of(delimiters, pos); 257 | 258 | // find next "non-delimiter" 259 | pos = str.find_first_of(delimiters, lastPos); 260 | } 261 | 262 | return tokens; 263 | } 264 | 265 | bool CanvasExport::FileExists(const std::string& fileName) 266 | { 267 | ai::UnicodeString aiFileName(fileName); 268 | ai::FilePath filePath(aiFileName); 269 | 270 | return filePath.Exists(true); 271 | } 272 | 273 | // Update bounds to include newBounds 274 | // TODO: Is there an Illustrator function to do this? 275 | void CanvasExport::UpdateBounds(const AIRealRect& newBounds, AIRealRect& bounds) 276 | { 277 | // Update minimums and maximums 278 | if (newBounds.top > bounds.top) 279 | { 280 | bounds.top = newBounds.top; 281 | } 282 | if (newBounds.left < bounds.left) 283 | { 284 | bounds.left = newBounds.left; 285 | } 286 | if (newBounds.bottom < bounds.bottom) 287 | { 288 | bounds.bottom = newBounds.bottom; 289 | } 290 | if (newBounds.right > bounds.right) 291 | { 292 | bounds.right = newBounds.right; 293 | } 294 | } 295 | 296 | // Find a unique filename 297 | // Path should have a trailing backslash ("c:\output\"), and extension should include a period (".png") 298 | std::string CanvasExport::GetUniqueFileName(const std::string& path, const std::string& fileName, const std::string& extension) 299 | { 300 | // Find a unique filename 301 | std::ostringstream uniqueFileName; 302 | 303 | // Find a unique file name 304 | int unique = 0; 305 | do 306 | { 307 | // Increment to make unique name 308 | unique++; 309 | 310 | // Generate a unique file name 311 | uniqueFileName.str(""); 312 | uniqueFileName << fileName << unique << extension; 313 | } while (FileExists((path + uniqueFileName.str()))); 314 | 315 | // Return unique file name 316 | return uniqueFileName.str(); 317 | } 318 | 319 | void CanvasExport::WriteArtTree() 320 | { 321 | AILayerHandle layerHandle = nullptr; 322 | ai::int32 layerCount = 0; 323 | 324 | // How many layers in this document? 325 | sAILayer->CountLayers(&layerCount); 326 | 327 | // Loop through all layers 328 | for (ai::int32 i = 0; i < layerCount; i++) 329 | { 330 | // Get a reference to the layer 331 | sAILayer->GetNthLayer(i, &layerHandle); 332 | 333 | // Get the first art in this layer 334 | AIArtHandle artHandle = nullptr; 335 | sAIArt->GetFirstArtOfLayer(layerHandle, &artHandle); 336 | 337 | // Dig in 338 | WriteArtTree(artHandle, 0); 339 | } 340 | } 341 | 342 | void CanvasExport::WriteArtTree(AIArtHandle artHandle, int depth) 343 | { 344 | // Simple way to describe art types for debugging purposes 345 | static const char *artTypes[] = 346 | { 347 | "kUnknownArt", "kGroupArt", "kPathArt", "kCompoundPathArt", "kTextArtUnsupported", "kTextPathArtUnsupported", "kTextRunArtUnsupported", "kPlacedArt", "kMysteryPathArt", "kRasterArt", "kPluginArt", "kMeshArt", "kTextFrameArt", "kSymbolArt", "kForeignArt", "kLegacyTextArt" 348 | }; 349 | 350 | // Loop through art and its siblings 351 | do 352 | { 353 | // Art type 354 | short type = 0; 355 | sAIArt->GetArtType(artHandle, &type); 356 | outFile << "\n//" << Indent(depth) << std::string(artTypes[type]) << " (" << type << ")"; 357 | 358 | // Get art name 359 | ai::UnicodeString artName; 360 | AIBoolean isDefaultName = false; 361 | sAIArt->GetArtName(artHandle, artName, &isDefaultName); 362 | outFile << ": " << artName.as_Platform(); 363 | 364 | // Any children? 365 | AIArtHandle childArtHandle; 366 | sAIArt->GetArtFirstChild(artHandle, &childArtHandle); 367 | if (childArtHandle != nullptr) 368 | { 369 | WriteArtTree(childArtHandle, depth + 1); 370 | } 371 | 372 | // Find the next sibling 373 | sAIArt->GetArtSibling(artHandle, &artHandle); 374 | } 375 | while (artHandle != nullptr); 376 | } 377 | -------------------------------------------------------------------------------- /Source/Utility.h: -------------------------------------------------------------------------------- 1 | // Utility.h 2 | // 3 | // Copyright (c) 2010-2022 Mike Swanson (http://blog.mikeswanson.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #ifndef UTILITY_H 24 | #define UTILITY_H 25 | 26 | #include "IllustratorSDK.h" 27 | #include "Ai2CanvasSuites.h" 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace CanvasExport 34 | { 35 | // Globals 36 | extern ofstream outFile; 37 | extern bool debug; 38 | 39 | bool OpenFile(const std::string& filePath); 40 | void CloseFile(); 41 | std::string Indent(size_t depth); 42 | void RenderTransform(const AIRealMatrix& matrix); 43 | void Replace(std::string& s, char find, char replace); 44 | void CleanString(std::string& s, AIBoolean camelCase); 45 | void CleanFunction(std::string& s); 46 | void CleanParameter(std::string& s); 47 | void ToLower(std::string& s); 48 | void MakeValidID(std::string& s); 49 | vector Tokenize(const std::string& str, const std::string& delimiters); 50 | bool FileExists(const std::string& fileName); 51 | void UpdateBounds(const AIRealRect& newBounds, AIRealRect& bounds); 52 | std::string GetUniqueFileName(const std::string& path, const std::string& fileName, const std::string& extension); 53 | void WriteArtTree(); 54 | void WriteArtTree(AIArtHandle artHandle, int depth); 55 | } 56 | #endif 57 | -------------------------------------------------------------------------------- /plugin.pipl: -------------------------------------------------------------------------------- 1 | ADBEkindSPEAADBEivrsADBEmi32ADBEpinm Ai2Canvas --------------------------------------------------------------------------------