Merge branch 'plantuml:master' into ImproveDoc

This commit is contained in:
The-Lum 2023-11-02 21:40:25 +01:00 committed by GitHub
commit 7666511512
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 513 additions and 4130 deletions

View File

@ -125,28 +125,20 @@
}
},
"node_modules/@babel/generator": {
"version": "7.15.8",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz",
"integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"dev": true,
"dependencies": {
"@babel/types": "^7.15.6",
"jsesc": "^2.5.1",
"source-map": "^0.5.0"
"@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/generator/node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@babel/helper-compilation-targets": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz",
@ -165,39 +157,35 @@
"@babel/core": "^7.0.0"
}
},
"node_modules/@babel/helper-function-name": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz",
"integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==",
"node_modules/@babel/helper-environment-visitor": {
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"dev": true,
"dependencies": {
"@babel/helper-get-function-arity": "^7.15.4",
"@babel/template": "^7.15.4",
"@babel/types": "^7.15.4"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-get-function-arity": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz",
"integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==",
"node_modules/@babel/helper-function-name": {
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dev": true,
"dependencies": {
"@babel/types": "^7.15.4"
"@babel/template": "^7.22.15",
"@babel/types": "^7.23.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-hoist-variables": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz",
"integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==",
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
"dev": true,
"dependencies": {
"@babel/types": "^7.15.4"
"@babel/types": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
@ -246,15 +234,6 @@
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-validator-identifier": {
"version": "7.15.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
"integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-optimise-call-expression": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz",
@ -304,21 +283,30 @@
}
},
"node_modules/@babel/helper-split-export-declaration": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz",
"integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==",
"version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"dependencies": {
"@babel/types": "^7.15.4"
"@babel/types": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
"integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true,
"engines": {
"node": ">=6.9.0"
@ -348,13 +336,13 @@
}
},
"node_modules/@babel/highlight": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
"integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
"integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"dev": true,
"dependencies": {
"@babel/helper-validator-identifier": "^7.14.5",
"chalk": "^2.0.0",
"@babel/helper-validator-identifier": "^7.22.20",
"chalk": "^2.4.2",
"js-tokens": "^4.0.0"
},
"engines": {
@ -362,9 +350,9 @@
}
},
"node_modules/@babel/parser": {
"version": "7.15.8",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz",
"integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
@ -536,44 +524,46 @@
}
},
"node_modules/@babel/template": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz",
"integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==",
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.14.5",
"@babel/parser": "^7.15.4",
"@babel/types": "^7.15.4"
"@babel/code-frame": "^7.22.13",
"@babel/parser": "^7.22.15",
"@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/template/node_modules/@babel/code-frame": {
"version": "7.15.8",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz",
"integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==",
"version": "7.22.13",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dev": true,
"dependencies": {
"@babel/highlight": "^7.14.5"
"@babel/highlight": "^7.22.13",
"chalk": "^2.4.2"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz",
"integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==",
"version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.14.5",
"@babel/generator": "^7.15.4",
"@babel/helper-function-name": "^7.15.4",
"@babel/helper-hoist-variables": "^7.15.4",
"@babel/helper-split-export-declaration": "^7.15.4",
"@babel/parser": "^7.15.4",
"@babel/types": "^7.15.4",
"@babel/code-frame": "^7.22.13",
"@babel/generator": "^7.23.0",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.23.0",
"@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
@ -582,39 +572,32 @@
}
},
"node_modules/@babel/traverse/node_modules/@babel/code-frame": {
"version": "7.15.8",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz",
"integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==",
"version": "7.22.13",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dev": true,
"dependencies": {
"@babel/highlight": "^7.14.5"
"@babel/highlight": "^7.22.13",
"chalk": "^2.4.2"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/types": {
"version": "7.15.6",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz",
"integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"dev": true,
"dependencies": {
"@babel/helper-validator-identifier": "^7.14.9",
"@babel/helper-string-parser": "^7.22.5",
"@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/types/node_modules/@babel/helper-validator-identifier": {
"version": "7.15.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
"integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@bcoe/v8-coverage": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
@ -1414,6 +1397,54 @@
"node": ">=8"
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
"dev": true,
"dependencies": {
"@jridgewell/set-array": "^1.0.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.9"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.19",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
"integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
"dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
@ -8506,22 +8537,15 @@
}
},
"@babel/generator": {
"version": "7.15.8",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz",
"integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"dev": true,
"requires": {
"@babel/types": "^7.15.6",
"jsesc": "^2.5.1",
"source-map": "^0.5.0"
},
"dependencies": {
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true
}
"@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
}
},
"@babel/helper-compilation-targets": {
@ -8536,33 +8560,29 @@
"semver": "^6.3.0"
}
},
"@babel/helper-function-name": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz",
"integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==",
"dev": true,
"requires": {
"@babel/helper-get-function-arity": "^7.15.4",
"@babel/template": "^7.15.4",
"@babel/types": "^7.15.4"
}
"@babel/helper-environment-visitor": {
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"dev": true
},
"@babel/helper-get-function-arity": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz",
"integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==",
"@babel/helper-function-name": {
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dev": true,
"requires": {
"@babel/types": "^7.15.4"
"@babel/template": "^7.22.15",
"@babel/types": "^7.23.0"
}
},
"@babel/helper-hoist-variables": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz",
"integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==",
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
"dev": true,
"requires": {
"@babel/types": "^7.15.4"
"@babel/types": "^7.22.5"
}
},
"@babel/helper-member-expression-to-functions": {
@ -8597,14 +8617,6 @@
"@babel/template": "^7.15.4",
"@babel/traverse": "^7.15.4",
"@babel/types": "^7.15.6"
},
"dependencies": {
"@babel/helper-validator-identifier": {
"version": "7.15.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
"integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
"dev": true
}
}
},
"@babel/helper-optimise-call-expression": {
@ -8644,18 +8656,24 @@
}
},
"@babel/helper-split-export-declaration": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz",
"integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==",
"version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"requires": {
"@babel/types": "^7.15.4"
"@babel/types": "^7.22.5"
}
},
"@babel/helper-string-parser": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
"dev": true
},
"@babel/helper-validator-identifier": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
"integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true
},
"@babel/helper-validator-option": {
@ -8676,20 +8694,20 @@
}
},
"@babel/highlight": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
"integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
"integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.14.5",
"chalk": "^2.0.0",
"@babel/helper-validator-identifier": "^7.22.20",
"chalk": "^2.4.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.15.8",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz",
"integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"dev": true
},
"@babel/plugin-syntax-async-generators": {
@ -8810,71 +8828,67 @@
}
},
"@babel/template": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz",
"integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==",
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.14.5",
"@babel/parser": "^7.15.4",
"@babel/types": "^7.15.4"
"@babel/code-frame": "^7.22.13",
"@babel/parser": "^7.22.15",
"@babel/types": "^7.22.15"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.15.8",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz",
"integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==",
"version": "7.22.13",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dev": true,
"requires": {
"@babel/highlight": "^7.14.5"
"@babel/highlight": "^7.22.13",
"chalk": "^2.4.2"
}
}
}
},
"@babel/traverse": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz",
"integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==",
"version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.14.5",
"@babel/generator": "^7.15.4",
"@babel/helper-function-name": "^7.15.4",
"@babel/helper-hoist-variables": "^7.15.4",
"@babel/helper-split-export-declaration": "^7.15.4",
"@babel/parser": "^7.15.4",
"@babel/types": "^7.15.4",
"@babel/code-frame": "^7.22.13",
"@babel/generator": "^7.23.0",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.23.0",
"@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.15.8",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz",
"integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==",
"version": "7.22.13",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dev": true,
"requires": {
"@babel/highlight": "^7.14.5"
"@babel/highlight": "^7.22.13",
"chalk": "^2.4.2"
}
}
}
},
"@babel/types": {
"version": "7.15.6",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz",
"integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.14.9",
"@babel/helper-string-parser": "^7.22.5",
"@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"dependencies": {
"@babel/helper-validator-identifier": {
"version": "7.15.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
"integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
"dev": true
}
}
},
"@bcoe/v8-coverage": {
@ -9488,6 +9502,45 @@
}
}
},
"@jridgewell/gen-mapping": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
"dev": true,
"requires": {
"@jridgewell/set-array": "^1.0.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.9"
}
},
"@jridgewell/resolve-uri": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
"dev": true
},
"@jridgewell/set-array": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
"dev": true
},
"@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true
},
"@jridgewell/trace-mapping": {
"version": "0.3.19",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
"integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
"dev": true,
"requires": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"@nodelib/fs.scandir": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",

11
attic.md Normal file
View File

@ -0,0 +1,11 @@
# Historical Code Archive
This document catalogs code that was previously part of PlantUML but has since been deprecated and removed due to its lack of use.
It serves as a historical reference to ensure we remember and understand past decisions.
- [logo language](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/logo)
- [basic language](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/jasic)
- [mjpeg export](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/mjpeg)
- [animation](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/anim)
- [ditherer quantization](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/quantization)
- [syntax suggestion](https://github.com/plantuml/plantuml/blob/v1.2023.12/src/net/sourceforge/plantuml/syntax/SyntaxChecker.java)

View File

@ -1,4 +1,4 @@
# Warning, "version" should be the same in gradle.properties and Version.java
# Any idea anyone how to magically synchronize those :-) ?
version = 1.2023.12beta1
version = 1.2023.13beta1
org.gradle.workers.max = 3

View File

@ -46,6 +46,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import net.sourceforge.plantuml.FileFormat;
import net.sourceforge.plantuml.FileFormatOption;
@ -84,10 +85,12 @@ import net.sourceforge.plantuml.security.SecurityUtils;
import net.sourceforge.plantuml.skin.UmlDiagramType;
import net.sourceforge.plantuml.skin.VisibilityModifier;
import net.sourceforge.plantuml.statediagram.StateDiagram;
import net.sourceforge.plantuml.stereo.Stereotype;
import net.sourceforge.plantuml.style.ClockwiseTopRightBottomLeft;
import net.sourceforge.plantuml.svek.CucaDiagramFileMaker;
import net.sourceforge.plantuml.svek.CucaDiagramFileMakerSvek;
import net.sourceforge.plantuml.text.BackSlash;
import net.sourceforge.plantuml.text.Guillemet;
import net.sourceforge.plantuml.xmi.CucaDiagramXmiMaker;
import net.sourceforge.plantuml.xmlsc.StateDiagramScxmlMaker;
@ -523,6 +526,41 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy,
return result;
}
@Override
public List<String> getVisibleStereotypeLabels(Entity entity) {
Stereotype stereotype = entity.getStereotype();
if (stereotype == null) {
return null;
}
List<EntityHideOrShow> commands = new ArrayList<>();
for (EntityHideOrShow hideOrShowEntry : hideOrShows) {
if (hideOrShowEntry.portion == EntityPortion.STEREOTYPE) {
commands.add(hideOrShowEntry);
}
}
List<String> visibleStereotypeLabels = new ArrayList<>();
for (String stereoTypeLabel: entity.getStereotype().getLabels(Guillemet.DOUBLE_COMPARATOR)) {
if (isHiddenStereotypeLabel(stereoTypeLabel, commands)) {
visibleStereotypeLabels.add(stereoTypeLabel);
}
}
return visibleStereotypeLabels;
}
private boolean isHiddenStereotypeLabel(String stereoTypeLabel, List<EntityHideOrShow> commands) {
for (EntityHideOrShow cmd : commands) {
String gender = cmd.gender.getGender();
if (gender != null && gender.equals(stereoTypeLabel)) {
return false;
}
}
return true;
}
public final void hideOrShow(EntityGender gender, EntityPortion portions, boolean show) {
for (EntityPortion portion : portions.asSet())
this.hideOrShows.add(new EntityHideOrShow(gender, portion, show));

View File

@ -37,8 +37,6 @@ package net.atmp;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@ -46,22 +44,16 @@ import java.io.OutputStream;
import java.util.Random;
import java.util.Set;
import javax.swing.ImageIcon;
import com.plantuml.api.cheerpj.WasmLog;
import net.sourceforge.plantuml.AnimatedGifEncoder;
import net.sourceforge.plantuml.AnnotatedBuilder;
import net.sourceforge.plantuml.AnnotatedWorker;
import net.sourceforge.plantuml.EmptyImageBuilder;
import net.sourceforge.plantuml.FileFormat;
import net.sourceforge.plantuml.FileFormatOption;
import net.sourceforge.plantuml.FileUtils;
import net.sourceforge.plantuml.OptionFlags;
import net.sourceforge.plantuml.Scale;
import net.sourceforge.plantuml.TitledDiagram;
import net.sourceforge.plantuml.anim.AffineTransformation;
import net.sourceforge.plantuml.anim.Animation;
import net.sourceforge.plantuml.api.ImageDataComplex;
import net.sourceforge.plantuml.api.ImageDataSimple;
import net.sourceforge.plantuml.braille.UGraphicBraille;
@ -87,14 +79,10 @@ import net.sourceforge.plantuml.klimt.drawing.tikz.UGraphicTikz;
import net.sourceforge.plantuml.klimt.drawing.txt.UGraphicTxt;
import net.sourceforge.plantuml.klimt.drawing.visio.UGraphicVdx;
import net.sourceforge.plantuml.klimt.font.StringBounder;
import net.sourceforge.plantuml.klimt.geom.MinMax;
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
import net.sourceforge.plantuml.klimt.shape.TextBlock;
import net.sourceforge.plantuml.klimt.shape.UDrawable;
import net.sourceforge.plantuml.klimt.shape.URectangle;
import net.sourceforge.plantuml.mjpeg.MJPEGGenerator;
import net.sourceforge.plantuml.security.SFile;
import net.sourceforge.plantuml.security.SImageIO;
import net.sourceforge.plantuml.skin.ColorParam;
import net.sourceforge.plantuml.skin.CornerParam;
import net.sourceforge.plantuml.skin.LineParam;
@ -113,9 +101,6 @@ import net.sourceforge.plantuml.url.Url;
public class ImageBuilder {
// ::comment when __CORE__
private Animation animation;
// ::done
private boolean annotations;
private HColor backcolor = getDefaultHBackColor();
@ -223,9 +208,6 @@ public class ImageBuilder {
public ImageBuilder styled(TitledDiagram diagram) {
skinParam = diagram.getSkinParam();
stringBounder = fileFormatOption.getDefaultStringBounder(skinParam);
// ::comment when __CORE__
animation = diagram.getAnimation();
// ::done
annotations = true;
backcolor = diagram.calculateBackColor();
margin = calculateMargin(diagram);
@ -246,21 +228,7 @@ public class ImageBuilder {
udrawable = annotatedWorker.addAdd((TextBlock) udrawable);
}
// ::comment when __CORE__
switch (fileFormatOption.getFileFormat()) {
case MJPEG:
return writeImageMjpeg(os);
case ANIMATED_GIF:
return writeImageAnimatedGif(os);
default:
return writeImageInternal(os, animation);
// ::done
// ::uncomment when __CORE__
// return writeImageInternal(os);
// ::done
// ::comment when __CORE__
}
// ::done
return writeImageInternal(os);
}
public byte[] writeByteArray() throws IOException {
@ -270,34 +238,16 @@ public class ImageBuilder {
}
}
// ::revert when __CORE__
private ImageData writeImageInternal(OutputStream os, Animation animationArg) throws IOException {
// private ImageData writeImageInternal(OutputStream os) throws IOException {
// ::done
private ImageData writeImageInternal(OutputStream os) throws IOException {
XDimension2D dim = getFinalDimension();
double dx = 0;
double dy = 0;
// ::comment when __CORE__
if (animationArg != null) {
final MinMax minmax = animationArg.getMinMax(dim);
animationArg.setDimension(dim);
dim = minmax.getDimension();
dx = -minmax.getMinX();
dy = -minmax.getMinY();
}
// ::done
final Scale scale = titledDiagram == null ? null : titledDiagram.getScale();
final double scaleFactor = (scale == null ? 1 : scale.getScale(dim.getWidth(), dim.getHeight())) * getDpi()
/ 96.0;
if (scaleFactor <= 0)
throw new IllegalStateException("Bad scaleFactor");
WasmLog.log("...image drawing...");
// ::revert when __CORE__
UGraphic ug = createUGraphic(dim, animationArg, dx, dy, scaleFactor,
UGraphic ug = createUGraphic(dim, scaleFactor,
titledDiagram == null ? new Pragma() : titledDiagram.getPragma());
// UGraphic ug = createUGraphic(dim, dx, dy, scaleFactor,
// titledDiagram == null ? new Pragma() : titledDiagram.getPragma());
// ::done
maybeDrawBorder(ug, dim);
if (randomPixel)
drawRandomPoint(ug);
@ -330,9 +280,9 @@ public class ImageBuilder {
if (stroke == null)
return;
final URectangle rectangle = URectangle.build(dim.getWidth() - stroke.getThickness(),
dim.getHeight() - stroke.getThickness())
.rounded(skinParam.getRoundCorner(CornerParam.diagramBorder, null));
final URectangle rectangle = URectangle
.build(dim.getWidth() - stroke.getThickness(), dim.getHeight() - stroke.getThickness())
.rounded(skinParam.getRoundCorner(CornerParam.diagramBorder, null));
ug.apply(color == null ? HColors.BLACK : color).apply(stroke).draw(rectangle);
}
@ -364,83 +314,13 @@ public class ImageBuilder {
return ug;
}
// ::comment when __CORE__
private ImageData writeImageMjpeg(OutputStream os) throws IOException {
final XDimension2D dim = getFinalDimension();
final SFile f = new SFile("c:/tmp.avi");
final int nbframe = 100;
final MJPEGGenerator m = new MJPEGGenerator(f, getAviImage(null).getWidth(null),
getAviImage(null).getHeight(null), 12.0, nbframe);
for (int i = 0; i < nbframe; i++) {
// AffineTransform at = AffineTransform.getRotateInstance(1.0);
AffineTransform at = AffineTransform.getTranslateInstance(dim.getWidth() / 2, dim.getHeight() / 2);
at.rotate(90.0 * Math.PI / 180.0 * i / 100);
at.translate(-dim.getWidth() / 2, -dim.getHeight() / 2);
// final AffineTransform at = AffineTransform.getTranslateInstance(i, 0);
// final ImageIcon ii = new ImageIcon(getAviImage(at));
// m.addImage(ii.getImage());
throw new UnsupportedOperationException();
}
m.finishAVI();
FileUtils.copyToStream(f, os);
return createImageData(dim);
}
private ImageData writeImageAnimatedGif(OutputStream os) throws IOException {
final XDimension2D dim = getFinalDimension();
final MinMax minmax = animation.getMinMax(dim);
final AnimatedGifEncoder e = new AnimatedGifEncoder();
// e.setQuality(1);
e.setRepeat(0);
e.start(os);
// e.setDelay(1000); // 1 frame per sec
// e.setDelay(100); // 10 frame per sec
e.setDelay(60); // 16 frame per sec
// e.setDelay(50); // 20 frame per sec
for (AffineTransformation at : animation.getAll()) {
final ImageIcon ii = new ImageIcon(getAviImage(at));
e.addFrame((BufferedImage) ii.getImage());
}
e.finish();
return createImageData(dim);
}
private Image getAviImage(AffineTransformation affineTransform) throws IOException {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
writeImageInternal(baos, Animation.singleton(affineTransform));
baos.close();
return SImageIO.read(baos.toByteArray());
}
// ::done
// ::revert when __CORE__
private UGraphic createUGraphic(final XDimension2D dim, Animation animationArg, double dx, double dy,
double scaleFactor, Pragma pragma) {
// private UGraphic createUGraphic(final XDimension2D dim, double dx, double dy,
// double scaleFactor, Pragma pragma) {
// ::done
private UGraphic createUGraphic(final XDimension2D dim, double scaleFactor, Pragma pragma) {
final ColorMapper colorMapper = fileFormatOption.getColorMapper();
switch (fileFormatOption.getFileFormat()) {
case PNG:
case RAW:
// ::comment when __CORE__
return createUGraphicPNG(scaleFactor, dim, animationArg, dx, dy, fileFormatOption.getWatermark(),
return createUGraphicPNG(scaleFactor, dim, fileFormatOption.getWatermark(),
fileFormatOption.getFileFormat());
// ::done
// ::uncomment when __CORE__
// return createUGraphicPNG(scaleFactor, dim, dx, dy,
// fileFormatOption.getWatermark(), fileFormatOption.getFileFormat());
// ::done
case SVG:
return createUGraphicSVG(scaleFactor, dim, pragma);
// ::comment when __CORE__
@ -492,14 +372,8 @@ public class ImageBuilder {
}
// ::uncomment when __CORE__
// private UGraphic createUGraphicPNG(double scaleFactor, final XDimension2D
// dim, double dx, double dy, String watermark, FileFormat format) {
// ::done
// ::comment when __CORE__
private UGraphic createUGraphicPNG(double scaleFactor, final XDimension2D dim, Animation affineTransforms,
double dx, double dy, String watermark, FileFormat format) {
// ::done
private UGraphic createUGraphicPNG(double scaleFactor, final XDimension2D dim, String watermark,
FileFormat format) {
Color pngBackColor = new Color(0, 0, 0, 0);
if (this.backcolor instanceof HColorSimple)
@ -513,15 +387,9 @@ public class ImageBuilder {
(int) (dim.getHeight() * scaleFactor), pngBackColor, stringBounder);
final Graphics2D graphics2D = builder.getGraphics2D();
// ::comment when __CORE__
final UGraphicG2d ug = new UGraphicG2d(backcolor, fileFormatOption.getColorMapper(), stringBounder, graphics2D,
scaleFactor, dx, dy, format, affineTransforms == null ? null : affineTransforms.getFirst());
// ::done
// ::uncomment when __CORE__
// final UGraphicG2d ug = new UGraphicG2d(backcolor,
// fileFormatOption.getColorMapper(), stringBounder, graphics2D,
// scaleFactor, dx, dy, format);
// ::done
scaleFactor, format);
ug.setBufferedImage(builder.getBufferedImage());
final BufferedImage im = ug.getBufferedImage();
if (this.backcolor instanceof HColorGradient)

View File

@ -76,8 +76,6 @@ public enum FileFormat {
SCXML("application/scxml+xml"), //
GRAPHML("application/graphml+xml"), //
PDF("application/pdf"), //
MJPEG("video/x-msvideo"), //
ANIMATED_GIF("image/gif"), //
HTML("text/html"), //
HTML5("text/html"), //
VDX("application/vnd.visio.xml"), //
@ -112,15 +110,9 @@ public enum FileFormat {
if (name().startsWith("XMI"))
return ".xmi";
if (this == MJPEG)
return ".avi";
if (this == LATEX || this == LATEX_NO_PREAMBLE)
return ".tex";
if (this == ANIMATED_GIF)
return ".gif";
if (this == BRAILLE_PNG)
return ".braille.png";

View File

@ -83,7 +83,7 @@ public class OptionFlags {
static public void setMaxPixel(int max) {
}
static public final boolean USE_HECTOR = false;
// static public final boolean USE_HECTOR = false;
static public boolean ADD_NICE_FOR_DOT = false;
// static public final boolean USE_IF_VERTICAL = true;

View File

@ -70,6 +70,7 @@ import net.sourceforge.plantuml.eggs.PSystemWelcomeFactory;
import net.sourceforge.plantuml.emoji.PSystemListEmojiFactory;
import net.sourceforge.plantuml.error.PSystemError;
import net.sourceforge.plantuml.error.PSystemErrorUtils;
import net.sourceforge.plantuml.error.PSystemUnsupported;
import net.sourceforge.plantuml.filesdiagram.FilesDiagramFactory;
import net.sourceforge.plantuml.flowdiagram.FlowDiagramFactory;
import net.sourceforge.plantuml.font.PSystemListFontsFactory;
@ -146,6 +147,9 @@ public class PSystemBuilder {
}
final DiagramType diagramType = umlSource.getDiagramType();
if (diagramType == DiagramType.UNKNOWN)
return new PSystemUnsupported(umlSource);
final List<PSystemError> errors = new ArrayList<>();
for (PSystemFactory systemFactory : factories) {
if (diagramType != systemFactory.getDiagramType())
@ -159,6 +163,8 @@ public class PSystemBuilder {
}
errors.add((PSystemError) sys);
}
if (errors.size() == 0)
return new PSystemUnsupported(umlSource);
result = PSystemErrorUtils.merge(errors);
return result;

View File

@ -42,8 +42,6 @@ import java.util.Map;
import net.atmp.ImageBuilder;
import net.sourceforge.plantuml.abel.DisplayPositioned;
import net.sourceforge.plantuml.abel.DisplayPositionned;
import net.sourceforge.plantuml.anim.Animation;
import net.sourceforge.plantuml.anim.AnimationDecoder;
import net.sourceforge.plantuml.api.ApiStable;
import net.sourceforge.plantuml.command.CommandExecutionResult;
import net.sourceforge.plantuml.core.Diagram;
@ -88,10 +86,6 @@ public abstract class TitledDiagram extends AbstractPSystem implements Diagram,
private final SkinParam skinParam;
// ::comment when __CORE__
private Animation animation;
// ::done
private final Pragma pragma = new Pragma();
public Pragma getPragma() {
@ -218,21 +212,6 @@ public abstract class TitledDiagram extends AbstractPSystem implements Diagram,
return ClockwiseTopRightBottomLeft.same(10);
}
// ::comment when __CORE__
final public void setAnimation(Iterable<CharSequence> animationData) {
// try {
final AnimationDecoder animationDecoder = new AnimationDecoder(animationData);
this.animation = Animation.create(animationDecoder.decode());
// } catch (ScriptException e) {
// Logme.error(e);
// }
}
final public Animation getAnimation() {
return animation;
}
// ::done
@Override
public ImageBuilder createImageBuilder(FileFormatOption fileFormatOption) throws IOException {
return super.createImageBuilder(fileFormatOption).styled(this);

View File

@ -38,10 +38,8 @@ package net.sourceforge.plantuml;
import static net.atmp.ImageBuilder.plainImageBuilder;
import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@ -74,10 +72,8 @@ import net.sourceforge.plantuml.klimt.shape.TextBlock;
import net.sourceforge.plantuml.klimt.shape.UDrawable;
import net.sourceforge.plantuml.klimt.shape.UImage;
import net.sourceforge.plantuml.log.Logme;
import net.sourceforge.plantuml.mjpeg.MJPEGGenerator;
import net.sourceforge.plantuml.pdf.PdfConverter;
import net.sourceforge.plantuml.security.SFile;
import net.sourceforge.plantuml.security.SImageIO;
import net.sourceforge.plantuml.security.SecurityUtils;
import net.sourceforge.plantuml.skin.UmlDiagramType;
import net.sourceforge.plantuml.style.NoStyleAvailableException;
@ -258,27 +254,6 @@ public abstract class UmlDiagram extends TitledDiagram implements Diagram, Annot
}
// ::comment when __CORE__
private void exportDiagramInternalMjpeg(OutputStream os) throws IOException {
final SFile f = new SFile("c:/test.avi");
final int nb = 150;
final double framerate = 30;
final MJPEGGenerator m = new MJPEGGenerator(f, 640, 480, framerate, nb);
for (int i = 0; i < nb; i++) {
final AffineTransform at = new AffineTransform();
final double coef = (nb - 1 - i) * 1.0 / nb;
at.setToShear(coef, coef);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
// exportDiagramTOxxBEREMOVED(baos, null, 0, new
// FileFormatOption(FileFormat.PNG, at));
baos.close();
final BufferedImage im = SImageIO.read(baos.toByteArray());
m.addImage(im);
}
m.finishAVI();
}
private ImageData exportDiagramInternalPdf(OutputStream os, int index) throws IOException {
final File svg = FileUtils.createTempFileLegacy("pdf", ".svf");
final File pdfFile = FileUtils.createTempFileLegacy("pdf", ".pdf");

View File

@ -37,4 +37,6 @@ package net.sourceforge.plantuml.abel;
public interface EntityGender {
public boolean contains(Entity test);
public String getGender();
}

View File

@ -44,6 +44,11 @@ public class EntityGenderUtils {
public boolean contains(Entity test) {
return test.getLeafType() == type;
}
@Override
public String getGender() {
return type.name();
}
};
}
@ -52,6 +57,11 @@ public class EntityGenderUtils {
public boolean contains(Entity test) {
return test.getUid().equals(entity.getUid());
}
@Override
public String getGender() {
return entity.getUid();
}
};
}
@ -61,7 +71,19 @@ public class EntityGenderUtils {
if (test.getStereotype() == null) {
return false;
}
return stereotype.equals(test.getStereotype().getLabel(Guillemet.DOUBLE_COMPARATOR));
for (String label : test.getStereotype().getLabels(Guillemet.DOUBLE_COMPARATOR)) {
if (label.equals(stereotype)) {
return true;
}
}
return false;
}
@Override
public String getGender() {
return stereotype;
}
};
}
@ -80,6 +102,11 @@ public class EntityGenderUtils {
}
return false;
}
@Override
public String getGender() {
return null;
}
};
}
@ -88,6 +115,11 @@ public class EntityGenderUtils {
public boolean contains(Entity test) {
return g1.contains(test) && g2.contains(test);
}
@Override
public String getGender() {
return null;
}
};
}
@ -96,6 +128,11 @@ public class EntityGenderUtils {
public boolean contains(Entity test) {
return true;
}
@Override
public String getGender() {
return null;
}
};
}
@ -104,6 +141,11 @@ public class EntityGenderUtils {
public boolean contains(Entity test) {
return test.getBodier().getMethodsToDisplay().size() == 0;
}
@Override
public String getGender() {
return null;
}
};
}
@ -112,7 +154,26 @@ public class EntityGenderUtils {
public boolean contains(Entity test) {
return test.getBodier().getFieldsToDisplay().size() == 0;
}
@Override
public String getGender() {
return null;
}
};
}
static public EntityGender byClassName(String className) {
return new EntityGender() {
@Override
public boolean contains(Entity test) {
return className.equals(test.getName());
}
@Override
public String getGender() {
return className;
}
};
}
}

View File

@ -1,157 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2024, Arnaud Roques
*
* Project Info: https://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.anim;
import java.awt.geom.AffineTransform;
import java.util.Objects;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sourceforge.plantuml.StringUtils;
import net.sourceforge.plantuml.klimt.geom.MinMax;
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
import net.sourceforge.plantuml.klimt.geom.XPoint2D;
public class AffineTransformation {
// ::remove folder when __HAXE__
// ::remove folder when __CORE__
static private final Pattern rotate = Pattern.compile("rotate\\s+(-?\\d+\\.?\\d*)");
static private final Pattern shear = Pattern.compile("shear\\s+(-?\\d+\\.?\\d*)\\s+(-?\\d+\\.?\\d*)");
static private final Pattern translate = Pattern.compile("translate\\s+(-?\\d+\\.?\\d*)\\s+(-?\\d+\\.?\\d*)");
static private final Pattern scale = Pattern.compile("scale\\s+(-?\\d+\\.?\\d*)\\s+(-?\\d+\\.?\\d*)");
static private final Pattern color = Pattern.compile("color\\s+.*");
private final AffineTransform affineTransform;
private XDimension2D dimension;
private AffineTransformation(AffineTransform affineTransform) {
this.affineTransform = Objects.requireNonNull(affineTransform);
}
private AffineTransformation compose(AffineTransformation other) {
final AffineTransform tmp = new AffineTransform(this.affineTransform);
tmp.concatenate(other.affineTransform);
return new AffineTransformation(tmp);
}
public static AffineTransformation from(AffineTransform affineTransform) {
return new AffineTransformation(affineTransform);
}
static AffineTransformation create(String value) {
final StringTokenizer st = new StringTokenizer(value, "|");
AffineTransformation result = null;
while (st.hasMoreTokens()) {
final String s = st.nextToken();
final AffineTransformation tmp = createSimple(s);
if (tmp != null) {
if (result == null) {
result = tmp;
} else {
result = result.compose(tmp);
}
}
}
return result;
}
private static AffineTransformation createSimple(String value) {
Matcher m = rotate.matcher(StringUtils.trin(value));
if (m.find()) {
final double angle = Double.parseDouble(m.group(1));
return new AffineTransformation(AffineTransform.getRotateInstance(angle * Math.PI / 180.0));
}
m = shear.matcher(value);
if (m.find()) {
final double shx = Double.parseDouble(m.group(1));
final double shy = Double.parseDouble(m.group(2));
return new AffineTransformation(AffineTransform.getShearInstance(shx, shy));
}
m = translate.matcher(value);
if (m.find()) {
final double tx = Double.parseDouble(m.group(1));
final double ty = Double.parseDouble(m.group(2));
return new AffineTransformation(AffineTransform.getTranslateInstance(tx, ty));
}
m = scale.matcher(value);
if (m.find()) {
final double scalex = Double.parseDouble(m.group(1));
final double scaley = Double.parseDouble(m.group(2));
return new AffineTransformation(AffineTransform.getScaleInstance(scalex, scaley));
}
m = color.matcher(value);
if (m.find()) {
return new AffineTransformation(new AffineTransform());
}
return null;
}
public final AffineTransform getAffineTransform() {
return getAffineTransform(dimension);
}
private AffineTransform getAffineTransform(XDimension2D dimension) {
if (dimension == null) {
throw new IllegalStateException();
}
final AffineTransform at = AffineTransform.getTranslateInstance(dimension.getWidth() / 2,
dimension.getHeight() / 2);
at.concatenate(affineTransform);
at.translate(-dimension.getWidth() / 2, -dimension.getHeight() / 2);
return at;
}
public void setDimension(XDimension2D dim) {
this.dimension = dim;
}
public MinMax getMinMax(XDimension2D rect) {
MinMax result = MinMax.getEmpty(false);
final AffineTransform tmp = getAffineTransform(rect);
result = result.addPoint(new XPoint2D(0, 0).transform(tmp));
result = result.addPoint(new XPoint2D(0, rect.getHeight()).transform(tmp));
result = result.addPoint(new XPoint2D(rect.getWidth(), 0).transform(tmp));
result = result.addPoint(new XPoint2D(rect.getWidth(), rect.getHeight()).transform(tmp));
return result;
}
}

View File

@ -1,99 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2024, Arnaud Roques
*
* Project Info: https://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.anim;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import net.sourceforge.plantuml.klimt.geom.MinMax;
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
public class Animation {
private final List<AffineTransformation> all;
private Animation(List<AffineTransformation> all) {
if (all.size() == 0) {
throw new IllegalArgumentException();
}
this.all = all;
}
public static Animation singleton(AffineTransformation affineTransformation) {
if (affineTransformation == null) {
return null;
}
return new Animation(Collections.singletonList(affineTransformation));
}
public static Animation create(List<String> descriptions) {
final List<AffineTransformation> all = new ArrayList<>();
for (String s : descriptions) {
final AffineTransformation tmp = AffineTransformation.create(s);
if (tmp != null) {
all.add(tmp);
}
}
return new Animation(all);
}
public Collection<AffineTransformation> getAll() {
return Collections.unmodifiableCollection(all);
}
public void setDimension(XDimension2D dim) {
for (AffineTransformation affineTransform : all) {
affineTransform.setDimension(dim);
}
}
public AffineTransformation getFirst() {
return all.get(0);
}
public MinMax getMinMax(XDimension2D dim) {
MinMax result = MinMax.getEmpty(false);
for (AffineTransformation affineTransform : all) {
final MinMax m = affineTransform.getMinMax(dim);
result = result.addMinMax(m);
}
return result;
}
}

View File

@ -1,78 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2024, Arnaud Roques
*
* Project Info: https://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.anim;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
public class AnimationDecoder {
private final List<String> result = new ArrayList<>();
public AnimationDecoder(Iterable<CharSequence> data) {
for (final Iterator<CharSequence> it = data.iterator(); it.hasNext();) {
String line = it.next().toString();
if (line.matches("^\\s*\\[script\\]\\s*$")) {
final StringBuilder scriptText = new StringBuilder();
while (true) {
line = it.next().toString();
if (line.matches("^\\s*\\[/script\\]\\s*$")) {
final AnimationScript script = new AnimationScript();
final String out = script.eval(scriptText.toString());
for (final StringTokenizer st = new StringTokenizer(out, "\n"); st.hasMoreTokens();) {
result.add(st.nextToken());
}
break;
} else {
scriptText.append(line);
scriptText.append("\n");
}
}
} else {
result.add(line);
}
}
}
public List<String> decode() {
return Collections.unmodifiableList(result);
}
}

View File

@ -1,71 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2024, Arnaud Roques
*
* Project Info: https://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.anim;
public class AnimationScript {
// private final ScriptEngine engine;
public AnimationScript() {
// final ScriptEngineManager manager = new ScriptEngineManager();
// engine = manager.getEngineByName("js");
// ScriptEngineManager manager = new ScriptEngineManager();
// List<ScriptEngineFactory> factories = manager.getEngineFactories();
// for (ScriptEngineFactory factory : factories) {
// System.out.println("Name : " + factory.getEngineName());
// System.out.println("Version : " + factory.getEngineVersion());
// System.out.println("Language name : " + factory.getLanguageName());
// System.out.println("Language version : " + factory.getLanguageVersion());
// System.out.println("Extensions : " + factory.getExtensions());
// System.out.println("Mime types : " + factory.getMimeTypes());
// System.out.println("Names : " + factory.getNames());
//
// }
}
public String eval(String line) {
throw new UnsupportedOperationException();
// final ScriptContext context = engine.getContext();
// final StringWriter sw = new StringWriter();
// context.setWriter(new PrintWriter(sw));
// engine.eval(line, context);
// final String result = sw.toString();
// return result;
}
}

View File

@ -190,30 +190,35 @@ public class CommandHideShowByGender extends SingleLineCommand2<UmlDiagram> {
} else {
arg1 = StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg1);
final Quark<Entity> quark = diagram.quarkInContext(true, diagram.cleanId(arg1));
Entity entity = quark.getData();
if (entity == null)
return CommandExecutionResult.error("No such element " + quark.getName());
gender = EntityGenderUtils.byEntityAlone(entity);
}
if (gender != null) {
final boolean empty = arg.get("EMPTY", 0) != null;
final boolean emptyMembers = empty && portion == EntityPortion.MEMBER;
if (empty == true && emptyMembers == false)
gender = EntityGenderUtils.and(gender, emptyByGender(portion));
if (diagram.getCurrentGroup().isRoot() == false)
gender = EntityGenderUtils.and(gender, EntityGenderUtils.byPackage(diagram.getCurrentGroup()));
if (emptyMembers) {
diagram.hideOrShow(EntityGenderUtils.and(gender, emptyByGender(EntityPortion.FIELD)),
EntityPortion.FIELD, arg.get("COMMAND", 0).equalsIgnoreCase("show"));
diagram.hideOrShow(EntityGenderUtils.and(gender, emptyByGender(EntityPortion.METHOD)),
EntityPortion.METHOD, arg.get("COMMAND", 0).equalsIgnoreCase("show"));
if (quark == null) {
return CommandExecutionResult.error("No such quark " + arg1);
}
if (portion == EntityPortion.METHOD) {
gender = EntityGenderUtils.byClassName(arg1);
} else {
diagram.hideOrShow(gender, portion, arg.get("COMMAND", 0).equalsIgnoreCase("show"));
Entity entity = quark.getData();
if (entity == null)
return CommandExecutionResult.error("No such element " + quark.getName());
gender = EntityGenderUtils.byEntityAlone(entity);
}
}
return CommandExecutionResult.ok();
final boolean empty = arg.get("EMPTY", 0) != null;
final boolean emptyMembers = empty && portion == EntityPortion.MEMBER;
if (empty && !emptyMembers)
gender = EntityGenderUtils.and(gender, emptyByGender(portion));
if (!diagram.getCurrentGroup().isRoot())
gender = EntityGenderUtils.and(gender, EntityGenderUtils.byPackage(diagram.getCurrentGroup()));
if (emptyMembers) {
diagram.hideOrShow(EntityGenderUtils.and(gender, emptyByGender(EntityPortion.FIELD)),
EntityPortion.FIELD, arg.get("COMMAND", 0).equalsIgnoreCase("show"));
diagram.hideOrShow(EntityGenderUtils.and(gender, emptyByGender(EntityPortion.METHOD)),
EntityPortion.METHOD, arg.get("COMMAND", 0).equalsIgnoreCase("show"));
} else {
diagram.hideOrShow(gender, portion, arg.get("COMMAND", 0).equalsIgnoreCase("show"));
}
return CommandExecutionResult.ok();
}
private EntityPortion getEntityPortion(String s) {

View File

@ -1,71 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2024, Arnaud Roques
*
* Project Info: https://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.command;
import java.util.Collections;
import net.sourceforge.plantuml.UmlDiagram;
import net.sourceforge.plantuml.regex.IRegex;
import net.sourceforge.plantuml.regex.RegexConcat;
import net.sourceforge.plantuml.regex.RegexLeaf;
import net.sourceforge.plantuml.regex.RegexResult;
import net.sourceforge.plantuml.utils.LineLocation;
public class CommandAffineTransform extends SingleLineCommand2<UmlDiagram> {
public static final CommandAffineTransform ME = new CommandAffineTransform();
private CommandAffineTransform() {
super(getRegexConcat());
}
static IRegex getRegexConcat() {
return RegexConcat.build(CommandAffineTransform.class.getName(), RegexLeaf.start(), //
new RegexLeaf("!transformation"), //
RegexLeaf.spaceOneOrMore(), //
new RegexLeaf("ANIMATION", "([^{}]*)"), RegexLeaf.end()); //
}
@Override
protected CommandExecutionResult executeArg(UmlDiagram diagram, LineLocation location, RegexResult arg) {
final CharSequence value = arg.get("ANIMATION", 0);
// ::comment when __CORE__
diagram.setAnimation(Collections.singletonList(value));
// ::done
return CommandExecutionResult.ok();
}
}

View File

@ -1,60 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2024, Arnaud Roques
*
* Project Info: https://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.command;
import net.sourceforge.plantuml.TitledDiagram;
import net.sourceforge.plantuml.utils.BlocLines;
public class CommandAffineTransformMultiline extends CommandMultilines<TitledDiagram> {
public static final CommandAffineTransformMultiline ME = new CommandAffineTransformMultiline();
private CommandAffineTransformMultiline() {
super("^!transformation[%s]+\\{[%s]*$");
}
@Override
public String getPatternEnd() {
return "^[%s]*!\\}[%s]*$";
}
public CommandExecutionResult execute(final TitledDiagram diagram, BlocLines lines) {
// lines = lines.subExtract(1, 1);
// diagram.setAnimation(lines);
return CommandExecutionResult.error("Not yet implemented");
}
}

View File

@ -73,8 +73,6 @@ public final class CommonCommands {
cmds.add(CommandScaleMaxWidth.ME);
cmds.add(CommandScaleMaxHeight.ME);
cmds.add(CommandScaleMaxWidthAndHeight.ME);
cmds.add(CommandAffineTransform.ME);
cmds.add(CommandAffineTransformMultiline.ME);
final CommandFactorySprite factorySpriteCommand = new CommandFactorySprite();
cmds.add(factorySpriteCommand.createMultiLine(false));
cmds.add(factorySpriteCommand.createSingleLine());

View File

@ -39,7 +39,7 @@ import net.sourceforge.plantuml.utils.StartUtils;
public enum DiagramType {
// ::remove folder when __HAXE__
UML, BPM, DITAA, DOT, PROJECT, JCCKIT, SALT, FLOW, CREOLE, JUNGLE, CUTE, MATH, LATEX, DEFINITION, GANTT, NW,
UML, BPM, DITAA, DOT, PROJECT, JCCKIT, SALT, FLOW, CREOLE, MATH, LATEX, DEFINITION, GANTT, NW,
MINDMAP, WBS, WIRE, JSON, GIT, BOARD, YAML, HCL, EBNF, REGEX, FILES, UNKNOWN;
static public DiagramType getTypeFromArobaseStart(String s) {
@ -59,11 +59,15 @@ public enum DiagramType {
if (StartUtils.startsWithSymbolAnd("startdot", s))
return DOT;
// ::comment when __CORE__ or __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__
if (StartUtils.startsWithSymbolAnd("startjcckit", s))
return JCCKIT;
// ::done
// ::comment when __CORE__ or __MIT__ or __EPL__ or __BSD__ or __ASL__
if (StartUtils.startsWithSymbolAnd("startditaa", s))
return DITAA;
// ::done
if (StartUtils.startsWithSymbolAnd("startproject", s))
return PROJECT;
@ -77,12 +81,6 @@ public enum DiagramType {
if (StartUtils.startsWithSymbolAnd("startcreole", s))
return CREOLE;
if (StartUtils.startsWithSymbolAnd("starttree", s))
return JUNGLE;
if (StartUtils.startsWithSymbolAnd("startcute", s))
return CUTE;
if (StartUtils.startsWithSymbolAnd("startmath", s))
return MATH;

View File

@ -45,7 +45,6 @@ import net.sourceforge.plantuml.klimt.creole.Display;
import net.sourceforge.plantuml.regex.Matcher2;
import net.sourceforge.plantuml.regex.MyPattern;
import net.sourceforge.plantuml.regex.Pattern2;
import net.sourceforge.plantuml.text.BackSlash;
import net.sourceforge.plantuml.text.StringLocated;
import net.sourceforge.plantuml.utils.LineLocation;
import net.sourceforge.plantuml.utils.StartUtils;

View File

@ -38,7 +38,11 @@ package net.sourceforge.plantuml.cucadiagram;
import net.sourceforge.plantuml.abel.Entity;
import net.sourceforge.plantuml.abel.EntityPortion;
import java.util.List;
public interface PortionShower {
boolean showPortion(EntityPortion portion, Entity entity);
List<String> getVisibleStereotypeLabels(Entity entity);
}

View File

@ -37,6 +37,7 @@ package net.sourceforge.plantuml.dot;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -101,6 +102,11 @@ final public class DotData implements PortionShower {
public boolean showPortion(EntityPortion portion, Entity entity) {
return true;
}
public List<String> getVisibleStereotypeLabels(Entity entity) {
return Collections.emptyList();
}
}, entityFactory, isHideEmptyDescriptionForState, dotMode, namespaceSeparator, pragma);
}
@ -136,6 +142,10 @@ final public class DotData implements PortionShower {
return portionShower.showPortion(portion, entity);
}
public List<String> getVisibleStereotypeLabels(Entity entity) {
return portionShower.getVisibleStereotypeLabels(entity);
}
public Entity getRootGroup() {
return entityFactory.getRootGroup();
}

View File

@ -48,10 +48,10 @@ class GraphvizLinux extends AbstractGraphviz {
@Override
protected File specificDotExe() {
final File all[] = new File[] { new File("/usr/local/bin/dot"), new File("/usr/bin/dot"),
new File("/opt/homebrew/bin/dot") };
final File all[] = new File[] { new File("/usr/local/bin/dot"), new File("/opt/homebrew/bin/dot"),
new File("/opt/homebrew/opt/graphviz/bin/dot"), new File("/usr/bin/dot") };
for (File f : all)
if (f.exists())
if (f.exists() && f.canRead() && f.canExecute())
return f;
return new File("/opt/local/bin/dot");
}

View File

@ -5,12 +5,12 @@
* (C) Copyright 2009-2024, Arnaud Roques
*
* Project Info: https://plantuml.com
*
*
* If you like this project or if you find it useful, you can support us at:
*
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
@ -30,31 +30,47 @@
*
*
* Original Author: Arnaud Roques
*
*
*
*/
package net.sourceforge.plantuml.logo;
package net.sourceforge.plantuml.error;
import net.sourceforge.plantuml.command.PSystemBasicFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.plantuml.FileFormatOption;
import net.sourceforge.plantuml.PlainDiagram;
import net.sourceforge.plantuml.core.DiagramDescription;
import net.sourceforge.plantuml.core.UmlSource;
import net.sourceforge.plantuml.klimt.shape.GraphicStrings;
import net.sourceforge.plantuml.klimt.shape.TextBlock;
import net.sourceforge.plantuml.klimt.shape.UDrawable;
import net.sourceforge.plantuml.version.License;
import net.sourceforge.plantuml.version.Version;
public class PSystemLogoFactory extends PSystemBasicFactory<PSystemLogo> {
public class PSystemUnsupported extends PlainDiagram {
@Override
public PSystemLogo initDiagram(UmlSource source, String startLine) {
return null;
private final List<String> strings = new ArrayList<>();
public PSystemUnsupported(UmlSource source) {
super(source);
strings.add("<b>Diagram not supported by this release of PlantUML");
strings.add(Version.fullDescription());
strings.add("License " + new License().toString());
}
@Override
public PSystemLogo executeLine(UmlSource source, PSystemLogo system, String line) {
if (system == null && line.equalsIgnoreCase("logo")) {
return new PSystemLogo(source);
}
if (system == null) {
return null;
}
system.doCommandLine(line);
return system;
protected UDrawable getRootDrawable(FileFormatOption fileFormatOption) throws IOException {
return getGraphicStrings();
}
public TextBlock getGraphicStrings() {
return GraphicStrings.createBlackOnWhite(strings);
}
public DiagramDescription getDescription() {
return new DiagramDescription("(Unsupported)");
}
}

View File

@ -1,829 +0,0 @@
package net.sourceforge.plantuml.jasic;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/*
Jasic uses the MIT License:
Copyright (c) 2010 Robert Nystrom
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
/*
* This defines a single class that contains an entire interpreter for a language very similar to the original BASIC.
* Everything is here (albeit in very simplified form): tokenizing, parsing, and interpretation. The file is organized
* in phases, with each appearing roughly in the order that they occur when a program is run. You should be able to read
* this top-down to walk through the entire process of loading and running a program.
*
* Jasic language syntax ---------------------
*
* Comments start with ' and proceed to the end of the line:
*
* print "hi there" ' this is a comment
*
* Numbers and strings are supported. Strings should be in "double quotes", and only positive integers can be parsed
* (though numbers are double internally).
*
* Variables are identified by name which must start with a letter and can contain letters or numbers. Case is
* significant for names and keywords.
*
* Each statement is on its own line. Optionally, a line may have a label before the statement. A label is a name that
* ends with a colon:
*
* foo:
*
*
* The following statements are supported:
*
* <name> = <expression> Evaluates the expression and assigns the result to the given named variable. All variables are
* globally scoped.
*
* pi = (314159 / 10000)
*
* print <expression> Evaluates the expression and prints the result.
*
* print "hello, " + "world"
*
* input <name> Reads in a line of input from the user and stores it in the variable with the given name.
*
* input guess
*
* goto <label> Jumps to the statement after the label with the given name.
*
* goto loop
*
* if <expression> then <label> Evaluates the expression. If it evaluates to a non-zero number, then jumps to the
* statement after the given label.
*
* if a < b then dosomething
*
*
* The following expressions are supported:
*
* <expression> = <expression> Evaluates to 1 if the two expressions are equal, 0 otherwise.
*
* <expression> + <expression> If the left-hand expression is a number, then adds the two expressions, otherwise
* concatenates the two strings.
*
* <expression> - <expression> <expression> * <expression> <expression> / <expression> <expression> < <expression>
* <expression> > <expression> You can figure it out.
*
* <name> A name in an expression simply returns the value of the variable with that name. If the variable was never
* set, it defaults to 0.
*
* All binary operators have the same precedence. Sorry, I had to cut corners somewhere.
*
* To keep things simple, I've omitted some stuff or hacked things a bit. When possible, I'll leave a "HACK" note there
* explaining what and why. If you make your own interpreter, you'll want to address those.
*
* @author Bob Nystrom
*/
public class Jasic {
// ::remove folder when __HAXE__
// ::remove folder when __CORE__
// ::remove folder when __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__
// Tokenizing (lexing) -----------------------------------------------------
/**
* This function takes a script as a string of characters and chunks it into a
* sequence of tokens. Each token is a meaningful unit of program, like a
* variable name, a number, a string, or an operator.
*/
private static List<Token> tokenize(String source) {
List<Token> tokens = new ArrayList<>();
String token = "";
TokenizeState state = TokenizeState.DEFAULT;
// Many tokens are a single character, like operators and ().
String charTokens = "\n=+-*/<>()";
TokenType[] tokenTypes = { TokenType.LINE, TokenType.EQUALS, TokenType.OPERATOR, TokenType.OPERATOR,
TokenType.OPERATOR, TokenType.OPERATOR, TokenType.OPERATOR, TokenType.OPERATOR, TokenType.LEFT_PAREN,
TokenType.RIGHT_PAREN };
// Scan through the code one character at a time, building up the list
// of tokens.
for (int i = 0; i < source.length(); i++) {
char c = source.charAt(i);
switch (state) {
case DEFAULT:
if (charTokens.indexOf(c) != -1) {
tokens.add(new Token(Character.toString(c), tokenTypes[charTokens.indexOf(c)]));
} else if (Character.isLetter(c)) {
token += c;
state = TokenizeState.WORD;
} else if (Character.isDigit(c)) {
token += c;
state = TokenizeState.NUMBER;
} else if (c == '"') {
state = TokenizeState.STRING;
} else if (c == '\'') {
state = TokenizeState.COMMENT;
}
break;
case WORD:
if (Character.isLetterOrDigit(c)) {
token += c;
} else if (c == ':') {
tokens.add(new Token(token, TokenType.LABEL));
token = "";
state = TokenizeState.DEFAULT;
} else {
tokens.add(new Token(token, TokenType.WORD));
token = "";
state = TokenizeState.DEFAULT;
i--; // Reprocess this character in the default state.
}
break;
case NUMBER:
// HACK: Negative numbers and floating points aren't supported.
// To get a negative number, just do 0 - <your number>.
// To get a floating point, divide.
if (Character.isDigit(c)) {
token += c;
} else {
tokens.add(new Token(token, TokenType.NUMBER));
token = "";
state = TokenizeState.DEFAULT;
i--; // Reprocess this character in the default state.
}
break;
case STRING:
if (c == '"') {
tokens.add(new Token(token, TokenType.STRING));
token = "";
state = TokenizeState.DEFAULT;
} else {
token += c;
}
break;
case COMMENT:
if (c == '\n') {
state = TokenizeState.DEFAULT;
}
break;
}
}
// HACK: Silently ignore any in-progress token when we run out of
// characters. This means that, for example, if a script has a string
// that's missing the closing ", it will just ditch it.
return tokens;
}
// Token data --------------------------------------------------------------
/**
* This defines the different kinds of tokens or meaningful chunks of code that
* the parser knows how to consume. These let us distinguish, for example,
* between a string "foo" and a variable named "foo".
*
* HACK: A typical tokenizer would actually have unique token types for each
* keyword (print, goto, etc.) so that the parser doesn't have to look at the
* names, but Jasic is a little more crude.
*/
private enum TokenType {
WORD, NUMBER, STRING, LABEL, LINE, EQUALS, OPERATOR, LEFT_PAREN, RIGHT_PAREN, EOF
}
/**
* This is a single meaningful chunk of code. It is created by the tokenizer and
* consumed by the parser.
*/
private static class Token {
public Token(String text, TokenType type) {
this.text = text;
this.type = type;
}
public final String text;
public final TokenType type;
}
/**
* This defines the different states the tokenizer can be in while it's scanning
* through the source code. Tokenizers are state machines, which means the only
* data they need to store is where they are in the source code and this one
* "state" or mode value.
*
* One of the main differences between tokenizing and parsing is this
* regularity. Because the tokenizer stores only this one state value, it can't
* handle nesting (which would require also storing a number to identify how
* deeply nested you are). The parser is able to handle that.
*/
private enum TokenizeState {
DEFAULT, WORD, NUMBER, STRING, COMMENT
}
// Parsing -----------------------------------------------------------------
/**
* This defines the Jasic parser. The parser takes in a sequence of tokens and
* generates an abstract syntax tree. This is the nested data structure that
* represents the series of statements, and the expressions (which can nest
* arbitrarily deeply) that they evaluate. In technical terms, what we have is a
* recursive descent parser, the simplest kind to hand-write.
*
* As a side-effect, this phase also stores off the line numbers for each label
* in the program. It's a bit gross, but it works.
*/
private class Parser {
public Parser(List<Token> tokens) {
this.tokens = tokens;
position = 0;
}
/**
* The top-level function to start parsing. This will keep consuming tokens and
* routing to the other parse functions for the different grammar syntax until
* we run out of code to parse.
*
* @param labels A map of label names to statement indexes. The parser will fill
* this in as it scans the code.
* @return The list of parsed statements.
*/
public List<Statement> parse(Map<String, Integer> labels) {
List<Statement> statements = new ArrayList<>();
while (true) {
// Ignore empty lines.
while (match(TokenType.LINE))
;
if (match(TokenType.LABEL)) {
// Mark the index of the statement after the label.
labels.put(last(1).text, statements.size());
} else if (match(TokenType.WORD, TokenType.EQUALS)) {
String name = last(2).text;
Expression value = expression();
statements.add(new AssignStatement(name, value));
} else if (match("print")) {
statements.add(new PrintStatement(expression()));
} else if (match("input")) {
statements.add(new InputStatement(consume(TokenType.WORD).text));
} else if (match("goto")) {
statements.add(new GotoStatement(consume(TokenType.WORD).text));
} else if (match("if")) {
Expression condition = expression();
consume("then");
String label = consume(TokenType.WORD).text;
statements.add(new IfThenStatement(condition, label));
} else
break; // Unexpected token (likely EOF), so end.
}
return statements;
}
// The following functions each represent one grammatical part of the
// language. If this parsed English, these functions would be named like
// noun() and verb().
/**
* Parses a single expression. Recursive descent parsers start with the
* lowest-precedent term and moves towards higher precedence. For Jasic, binary
* operators (+, -, etc.) are the lowest.
*
* @return The parsed expression.
*/
private Expression expression() {
return operator();
}
/**
* Parses a series of binary operator expressions into a single expression. In
* Jasic, all operators have the same predecence and associate left-to-right.
* That means it will interpret: 1 + 2 * 3 - 4 / 5 like: ((((1 + 2) * 3) - 4) /
* 5)
*
* It works by building the expression tree one at a time. So, given this code:
* 1 + 2 * 3, this will:
*
* 1. Parse (1) as an atomic expression. 2. See the (+) and start a new operator
* expression. 3. Parse (2) as an atomic expression. 4. Build a (1 + 2)
* expression and replace (1) with it. 5. See the (*) and start a new operator
* expression. 6. Parse (3) as an atomic expression. 7. Build a ((1 + 2) * 3)
* expression and replace (1 + 2) with it. 8. Return the last expression built.
*
* @return The parsed expression.
*/
private Expression operator() {
Expression expression = atomic();
// Keep building operator expressions as long as we have operators.
while (match(TokenType.OPERATOR) || match(TokenType.EQUALS)) {
char operator = last(1).text.charAt(0);
Expression right = atomic();
expression = new OperatorExpression(expression, operator, right);
}
return expression;
}
/**
* Parses an "atomic" expression. This is the highest level of precedence and
* contains single literal tokens like 123 and "foo", as well as parenthesized
* expressions.
*
* @return The parsed expression.
*/
private Expression atomic() {
if (match(TokenType.WORD)) {
// A word is a reference to a variable.
return new VariableExpression(last(1).text);
} else if (match(TokenType.NUMBER)) {
return new NumberValue(Double.parseDouble(last(1).text));
} else if (match(TokenType.STRING)) {
return new StringValue(last(1).text);
} else if (match(TokenType.LEFT_PAREN)) {
// The contents of a parenthesized expression can be any
// expression. This lets us "restart" the precedence cascade
// so that you can have a lower precedence expression inside
// the parentheses.
Expression expression = expression();
consume(TokenType.RIGHT_PAREN);
return expression;
}
throw new Error("Couldn't parse :(");
}
// The following functions are the core low-level operations that the
// grammar parser is built in terms of. They match and consume tokens in
// the token stream.
/**
* Consumes the next two tokens if they are the given type (in order). Consumes
* no tokens if either check fais.
*
* @param type1 Expected type of the next token.
* @param type2 Expected type of the subsequent token.
* @return True if tokens were consumed.
*/
private boolean match(TokenType type1, TokenType type2) {
if (get(0).type != type1)
return false;
if (get(1).type != type2)
return false;
position += 2;
return true;
}
/**
* Consumes the next token if it's the given type.
*
* @param type Expected type of the next token.
* @return True if the token was consumed.
*/
private boolean match(TokenType type) {
if (get(0).type != type)
return false;
position++;
return true;
}
/**
* Consumes the next token if it's a word token with the given name.
*
* @param name Expected name of the next word token.
* @return True if the token was consumed.
*/
private boolean match(String name) {
if (get(0).type != TokenType.WORD)
return false;
if (!get(0).text.equals(name))
return false;
position++;
return true;
}
/**
* Consumes the next token if it's the given type. If not, throws an exception.
* This is for cases where the parser demands a token of a certain type in a
* certain position, for example a matching ) after an opening (.
*
* @param type Expected type of the next token.
* @return The consumed token.
*/
private Token consume(TokenType type) {
if (get(0).type != type)
throw new Error("Expected " + type + ".");
return tokens.get(position++);
}
/**
* Consumes the next token if it's a word with the given name. If not, throws an
* exception.
*
* @param name Expected name of the next word token.
* @return The consumed token.
*/
private Token consume(String name) {
if (!match(name))
throw new Error("Expected " + name + ".");
return last(1);
}
/**
* Gets a previously consumed token, indexing backwards. last(1) will be the
* token just consumed, last(2) the one before that, etc.
*
* @param offset How far back in the token stream to look.
* @return The consumed token.
*/
private Token last(int offset) {
return tokens.get(position - offset);
}
/**
* Gets an unconsumed token, indexing forward. get(0) will be the next token to
* be consumed, get(1) the one after that, etc.
*
* @param offset How far forward in the token stream to look.
* @return The yet-to-be-consumed token.
*/
private Token get(int offset) {
if (position + offset >= tokens.size()) {
return new Token("", TokenType.EOF);
}
return tokens.get(position + offset);
}
private final List<Token> tokens;
private int position;
}
// Abstract syntax tree (AST) ----------------------------------------------
// These classes define the syntax tree data structures. This is how code is
// represented internally in a way that's easy for the interpreter to
// understand.
//
// HACK: Unlike most real compilers or interpreters, the logic to execute
// the code is baked directly into these classes. Typically, it would be
// separated out so that the AST us just a static data structure.
/**
* Base interface for a Jasic statement. The different supported statement types
* like "print" and "goto" implement this.
*/
public interface Statement {
/**
* Statements implement this to actually perform whatever behavior the statement
* causes. "print" statements will display text here, "goto" statements will
* change the current statement, etc.
*/
void execute();
}
/**
* Base interface for an expression. An expression is like a statement except
* that it also returns a value when executed. Expressions do not appear at the
* top level in Jasic programs, but are used in many statements. For example,
* the value printed by a "print" statement is an expression. Unlike statements,
* expressions can nest.
*/
public interface Expression {
/**
* Expression classes implement this to evaluate the expression and return the
* value.
*
* @return The value of the calculated expression.
*/
Value evaluate();
}
/**
* A "print" statement evaluates an expression, converts the result to a string,
* and displays it to the user.
*/
public class PrintStatement implements Statement {
public PrintStatement(Expression expression) {
this.expression = expression;
}
public void execute() {
System.out.println(expression.evaluate().toString());
}
private final Expression expression;
}
/**
* An "input" statement reads input from the user and stores it in a variable.
*/
public class InputStatement implements Statement {
public InputStatement(String name) {
this.name = name;
}
public void execute() {
try {
String input = lineIn.readLine();
// Store it as a number if possible, otherwise use a string.
try {
double value = Double.parseDouble(input);
variables.put(name, new NumberValue(value));
} catch (NumberFormatException e) {
variables.put(name, new StringValue(input));
}
} catch (IOException e1) {
// HACK: Just ignore the problem.
}
}
private final String name;
}
/**
* An assignment statement evaluates an expression and stores the result in a
* variable.
*/
public class AssignStatement implements Statement {
public AssignStatement(String name, Expression value) {
this.name = name;
this.value = value;
}
public void execute() {
variables.put(name, value.evaluate());
}
private final String name;
private final Expression value;
}
/**
* A "goto" statement jumps execution to another place in the program.
*/
public class GotoStatement implements Statement {
public GotoStatement(String label) {
this.label = label;
}
public void execute() {
if (labels.containsKey(label)) {
currentStatement = labels.get(label).intValue();
}
}
private final String label;
}
/**
* An if then statement jumps execution to another place in the program, but
* only if an expression evaluates to something other than 0.
*/
public class IfThenStatement implements Statement {
public IfThenStatement(Expression condition, String label) {
this.condition = condition;
this.label = label;
}
public void execute() {
if (labels.containsKey(label)) {
double value = condition.evaluate().toNumber();
if (value != 0) {
currentStatement = labels.get(label).intValue();
}
}
}
private final Expression condition;
private final String label;
}
/**
* A variable expression evaluates to the current value stored in that variable.
*/
public class VariableExpression implements Expression {
public VariableExpression(String name) {
this.name = name;
}
public Value evaluate() {
if (variables.containsKey(name)) {
return variables.get(name);
}
return new NumberValue(0);
}
private final String name;
}
/**
* An operator expression evaluates two expressions and then performs some
* arithmetic operation on the results.
*/
public class OperatorExpression implements Expression {
public OperatorExpression(Expression left, char operator, Expression right) {
this.left = left;
this.operator = operator;
this.right = right;
}
public Value evaluate() {
Value leftVal = left.evaluate();
Value rightVal = right.evaluate();
switch (operator) {
case '=':
// Coerce to the left argument's type, then compare.
if (leftVal instanceof NumberValue) {
return new NumberValue((leftVal.toNumber() == rightVal.toNumber()) ? 1 : 0);
} else {
return new NumberValue(leftVal.toString().equals(rightVal.toString()) ? 1 : 0);
}
case '+':
// Addition if the left argument is a number, otherwise do
// string concatenation.
if (leftVal instanceof NumberValue) {
return new NumberValue(leftVal.toNumber() + rightVal.toNumber());
} else {
return new StringValue(leftVal.toString() + rightVal.toString());
}
case '-':
return new NumberValue(leftVal.toNumber() - rightVal.toNumber());
case '*':
return new NumberValue(leftVal.toNumber() * rightVal.toNumber());
case '/':
return new NumberValue(leftVal.toNumber() / rightVal.toNumber());
case '<':
// Coerce to the left argument's type, then compare.
if (leftVal instanceof NumberValue) {
return new NumberValue((leftVal.toNumber() < rightVal.toNumber()) ? 1 : 0);
} else {
return new NumberValue((leftVal.toString().compareTo(rightVal.toString()) < 0) ? 1 : 0);
}
case '>':
// Coerce to the left argument's type, then compare.
if (leftVal instanceof NumberValue) {
return new NumberValue((leftVal.toNumber() > rightVal.toNumber()) ? 1 : 0);
} else {
return new NumberValue((leftVal.toString().compareTo(rightVal.toString()) > 0) ? 1 : 0);
}
}
throw new Error("Unknown operator.");
}
private final Expression left;
private final char operator;
private final Expression right;
}
// Value types -------------------------------------------------------------
/**
* This is the base interface for a value. Values are the data that the
* interpreter processes. They are what gets stored in variables, printed, and
* operated on.
*
* There is an implementation of this interface for each of the different
* primitive types (really just double and string) that Jasic supports. Wrapping
* them in a single Value interface lets Jasic be dynamically-typed and convert
* between different representations as needed.
*
* Note that Value extends Expression. This is a bit of a hack, but it lets us
* use values (which are typically only ever seen by the interpreter and not the
* parser) as both runtime values, and as object representing literals in code.
*/
public interface Value extends Expression {
/**
* Value types override this to convert themselves to a string representation.
*/
String toString();
/**
* Value types override this to convert themselves to a numeric representation.
*/
double toNumber();
}
/**
* A numeric value. Jasic uses doubles internally for all numbers.
*/
public class NumberValue implements Value {
public NumberValue(double value) {
this.value = value;
}
@Override
public String toString() {
return Double.toString(value);
}
public double toNumber() {
return value;
}
public Value evaluate() {
return this;
}
private final double value;
}
/**
* A string value.
*/
public class StringValue implements Value {
public StringValue(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
public double toNumber() {
return Double.parseDouble(value);
}
public Value evaluate() {
return this;
}
private final String value;
}
// Interpreter -------------------------------------------------------------
/**
* Constructs a new Jasic instance. The instance stores the global state of the
* interpreter such as the values of all of the variables and the current
* statement.
*/
public Jasic() {
variables = new HashMap<String, Value>();
labels = new HashMap<String, Integer>();
InputStreamReader converter = new InputStreamReader(System.in);
lineIn = new BufferedReader(converter);
}
/**
* This is where the magic happens. This runs the code through the parsing
* pipeline to generate the AST. Then it executes each statement. It keeps track
* of the current line in a member variable that the statement objects have
* access to. This lets "goto" and "if then" do flow control by simply setting
* the index of the current statement.
*
* In an interpreter that didn't mix the interpretation logic in with the AST
* node classes, this would be doing a lot more work.
*
* @param source A string containing the source code of a .jas script to
* interpret.
*/
public void interpret(String source) {
// Tokenize.
List<Token> tokens = tokenize(source);
// Parse.
Parser parser = new Parser(tokens);
List<Statement> statements = parser.parse(labels);
// Interpret until we're done.
currentStatement = 0;
while (currentStatement < statements.size()) {
int thisStatement = currentStatement;
currentStatement++;
statements.get(thisStatement).execute();
}
}
private final Map<String, Value> variables;
private final Map<String, Integer> labels;
private final BufferedReader lineIn;
private int currentStatement;
}

View File

@ -37,7 +37,6 @@ package net.sourceforge.plantuml.klimt.drawing.g2d;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
@ -50,7 +49,6 @@ import java.util.Objects;
import java.util.Set;
import net.sourceforge.plantuml.FileFormat;
import net.sourceforge.plantuml.anim.AffineTransformation;
import net.sourceforge.plantuml.klimt.UAntiAliasing;
import net.sourceforge.plantuml.klimt.UChange;
import net.sourceforge.plantuml.klimt.UClip;
@ -88,10 +86,6 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
private List<Url> urls = new ArrayList<>();
private Set<Url> allUrls = new HashSet<>();
// ::comment when __CORE__
private final boolean hasAffineTransform;
// ::done
public final Set<Url> getAllUrlsEncountered() {
return Collections.unmodifiableSet(allUrls);
}
@ -114,9 +108,6 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
private UGraphicG2d(UGraphicG2d other) {
super(other.getStringBounder());
copy(other);
// ::comment when __CORE__
this.hasAffineTransform = other.hasAffineTransform;
// ::done
this.dpiFactor = other.dpiFactor;
this.bufferedImage = other.bufferedImage;
this.urls = other.urls;
@ -128,20 +119,6 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d,
double dpiFactor, FileFormat format) {
// ::revert when __CORE__
this(defaultBackground, colorMapper, stringBounder, g2d, dpiFactor, 0, 0, format, null);
// this(defaultBackground, colorMapper, stringBounder, g2d, dpiFactor, 0, 0,
// format);
// ::done
}
// ::revert when __CORE__
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d,
double dpiFactor, double dx, double dy, FileFormat format, AffineTransformation affineTransform) {
// public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper,
// StringBounder stringBounder, Graphics2D g2d,
// double dpiFactor, double dx, double dy, FileFormat format) {
// ::done
super(stringBounder);
copy(defaultBackground, colorMapper, g2d);
this.format = format;
@ -149,21 +126,13 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
if (dpiFactor != 1.0)
g2d.scale(dpiFactor, dpiFactor);
// ::comment when __CORE__
this.hasAffineTransform = affineTransform != null;
if (this.hasAffineTransform) {
if (dx != 0 || dy != 0)
getGraphicObject().transform(AffineTransform.getTranslateInstance(dx, dy));
getGraphicObject().transform(affineTransform.getAffineTransform());
}
// ::done
register(dpiFactor);
}
private void register(double dpiFactor) {
registerDriver(URectangle.class, new DriverRectangleG2d(dpiFactor, this));
// ::comment when __CORE__
if (this.hasAffineTransform || dpiFactor != 1.0)
if (dpiFactor != 1.0)
registerDriver(UText.class, new DriverTextAsPathG2d(this, getStringBounder()));
else
// ::done

View File

@ -1,174 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2024, Arnaud Roques
*
* Project Info: https://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.logo;
import java.util.HashMap;
import java.util.Map;
class LogoScanner {
// ::remove folder when __HAXE__
// ::remove folder when __CORE__
// ::remove folder when __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__
final private Map<String, Integer> keywordTable = new HashMap<String, Integer>();
private char sourceString[];
private int sourceLength;
private int i;
public LogoScanner() {
keywordTable.put("forward", LogoToken.FORWARD);
keywordTable.put("fd", LogoToken.FORWARD);
keywordTable.put("back", LogoToken.BACK);
keywordTable.put("bk", LogoToken.BACK);
keywordTable.put("right", LogoToken.RIGHT);
keywordTable.put("rt", LogoToken.RIGHT);
keywordTable.put("left", LogoToken.LEFT);
keywordTable.put("lt", LogoToken.LEFT);
keywordTable.put("penup", LogoToken.PENUP);
keywordTable.put("pu", LogoToken.PENUP);
keywordTable.put("pendown", LogoToken.PENDOWN);
keywordTable.put("pd", LogoToken.PENDOWN);
keywordTable.put("hideturtle", LogoToken.HIDETURTLE);
keywordTable.put("ht", LogoToken.HIDETURTLE);
keywordTable.put("showturtle", LogoToken.SHOWTURTLE);
keywordTable.put("st", LogoToken.SHOWTURTLE);
keywordTable.put("clearscreen", LogoToken.CLEARSCREEN);
keywordTable.put("cs", LogoToken.CLEARSCREEN);
keywordTable.put("repeat", LogoToken.REPEAT);
keywordTable.put("rep", LogoToken.REPEAT);
keywordTable.put("to", LogoToken.TO);
keywordTable.put("setpc", LogoToken.SETPC);
keywordTable.put("pc", LogoToken.SETPC);
}
public int getPosition() {
return i;
}
public void setPosition(int newPosition) {
if (i >= 0 && i <= sourceLength) {
i = newPosition;
} else {
i = sourceLength;
}
}
public void setSourceString(String newSourceString) {
sourceLength = newSourceString.length();
sourceString = newSourceString.concat("\0").toCharArray();
i = 0;
}
public String getSourceString() {
return new String(sourceString);
}
public String getRestAsString() {
skipWhitespace();
final String rest = new String(sourceString, i, sourceLength - i + 1);
i = sourceLength;
return rest;
}
void skipWhitespace() {
char c;
do {
c = sourceString[i++];
} while (c == ' ' || c == '\t');
i--;
}
public LogoToken getToken() {
final LogoToken token = new LogoToken();
final StringBuilder lexeme = new StringBuilder();
if (i >= sourceLength) {
token.kind = LogoToken.END_OF_INPUT;
return token;
}
// Skip whitespace.
skipWhitespace();
char c = sourceString[i++];
// Now figure out what kind of token we've got.
if (c == '[' || c == ']') {
token.kind = c;
token.lexeme = String.valueOf(c);
} else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
do {
lexeme.append(c);
c = sourceString[i++];
} while ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
i--;
token.lexeme = lexeme.toString();
token.kind = LogoToken.IDENTIFIER;
final Integer keyword = keywordTable.get(token.lexeme);
if (keyword != null) {
token.kind = keyword;
}
} else if (c >= '0' && c <= '9') {
do {
lexeme.append(c);
c = sourceString[i++];
} while (c >= '0' && c <= '9');
boolean hasDecimalPart = false;
if (c == '.') {
do {
lexeme.append(c);
c = sourceString[i++];
} while (c >= '0' && c <= '9');
hasDecimalPart = true;
}
i--;
token.lexeme = lexeme.toString();
token.value = Float.parseFloat(token.lexeme);
if (hasDecimalPart) {
token.kind = LogoToken.FLOAT;
} else {
token.kind = LogoToken.INTEGER;
token.intValue = Integer.parseInt(token.lexeme);
}
} else if (c == 0) {
i--;
token.kind = LogoToken.END_OF_INPUT;
} else {
i--;
token.kind = LogoToken.INVALID_TOKEN;
}
return token;
}
}

View File

@ -1,62 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2024, Arnaud Roques
*
* Project Info: https://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.logo;
class LogoToken {
public final static int END_OF_INPUT = 256;
public final static int INVALID_TOKEN = 257;
public final static int IDENTIFIER = 258;
public final static int FLOAT = 259;
public final static int INTEGER = 270;
public final static int FORWARD = 260;
public final static int BACK = 261;
public final static int LEFT = 262;
public final static int RIGHT = 263;
public final static int PENUP = 264;
public final static int PENDOWN = 265;
public final static int HIDETURTLE = 266;
public final static int SHOWTURTLE = 267;
public final static int CLEARSCREEN = 268;
public final static int REPEAT = 269;
public final static int TO = 271;
public final static int SETPC = 272;
public int kind;
public String lexeme;
public float value;
public int intValue;
}

View File

@ -1,109 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2024, Arnaud Roques
*
* Project Info: https://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.logo;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.plantuml.AbstractPSystem;
import net.sourceforge.plantuml.EmptyImageBuilder;
import net.sourceforge.plantuml.FileFormat;
import net.sourceforge.plantuml.FileFormatOption;
import net.sourceforge.plantuml.api.ImageDataSimple;
import net.sourceforge.plantuml.core.DiagramDescription;
import net.sourceforge.plantuml.core.ImageData;
import net.sourceforge.plantuml.core.UmlSource;
import net.sourceforge.plantuml.klimt.color.ColorMapper;
import net.sourceforge.plantuml.klimt.color.HColors;
import net.sourceforge.plantuml.klimt.drawing.UGraphic;
import net.sourceforge.plantuml.klimt.drawing.g2d.UGraphicG2d;
import net.sourceforge.plantuml.klimt.font.StringBounder;
import net.sourceforge.plantuml.png.PngIO;
public class PSystemLogo extends AbstractPSystem {
private final List<String> lines = new ArrayList<>();
public PSystemLogo(UmlSource source) {
super(source);
}
@Override
final protected ImageData exportDiagramNow(OutputStream os, int num, FileFormatOption fileFormat)
throws IOException {
final int width = 640;
final int height = 480;
final StringBounder stringBounder = FileFormat.PNG.getDefaultStringBounder();
final EmptyImageBuilder builder = new EmptyImageBuilder(fileFormat.getWatermark(), width, height, Color.WHITE,
stringBounder);
final BufferedImage im = builder.getBufferedImage();
final UGraphic ug = new UGraphicG2d(HColors.WHITE, ColorMapper.IDENTITY, stringBounder, builder.getGraphics2D(),
1.0, FileFormat.PNG);
((UGraphicG2d) ug).setBufferedImage(im);
final TurtleGraphicsPane turtleGraphicsPane = new TurtleGraphicsPane(width, height);
final TinyJavaLogo tinyJavaLogo = new TinyJavaLogo(turtleGraphicsPane);
for (String line : lines) {
tinyJavaLogo.doCommandLine(line);
}
turtleGraphicsPane.paint(ug);
PngIO.write(im, ColorMapper.IDENTITY, os, null, 96);
return new ImageDataSimple(im.getWidth(), im.getHeight());
}
// private GraphicStrings getGraphicStrings() throws IOException {
// final UFont font = new UFont("SansSerif", Font.PLAIN, 12);
// final GraphicStrings result = new GraphicStrings(strings, font,
// HtmlColorUtils.BLACK, HtmlColorUtils.WHITE,
// image,
// GraphicPosition.BOTTOM, false);
// result.setMinWidth(200);
// return result;
// }
public DiagramDescription getDescription() {
return new DiagramDescription("(Logo)");
}
public void doCommandLine(String line) {
lines.add(line);
}
}

View File

@ -1,229 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2024, Arnaud Roques
*
* Project Info: https://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.logo;
import java.util.HashMap;
import java.util.Map;
import net.sourceforge.plantuml.klimt.color.HColor;
import net.sourceforge.plantuml.klimt.color.HColorSet;
public class TinyJavaLogo {
private final LogoScanner scanner = new LogoScanner();
private final TurtleGraphicsPane turtleGraphicsPane;
private final Map<String, String> dictionary = new HashMap<String, String>();
private HColor penColor;
public TinyJavaLogo(TurtleGraphicsPane turtleGraphicsPane) {
this.turtleGraphicsPane = turtleGraphicsPane;
}
private void message(String messageText) {
// turtleGraphicsPane.message(messageText);
}
private void error(String messageText) {
turtleGraphicsPane.message("Error: " + messageText);
}
private void parseCommandBlock(int nestLevel) {
String commandName;
String code;
LogoToken token = scanner.getToken();
while (token.kind != LogoToken.END_OF_INPUT && token.kind != LogoToken.INVALID_TOKEN) {
switch (token.kind) {
case LogoToken.FORWARD:
token = scanner.getToken();
if (token.kind == LogoToken.FLOAT || token.kind == LogoToken.INTEGER) {
turtleGraphicsPane.forward(token.value);
token = scanner.getToken();
} else {
error("FORWARD requires distance");
return;
}
break;
case LogoToken.BACK:
token = scanner.getToken();
if (token.kind == LogoToken.FLOAT || token.kind == LogoToken.INTEGER) {
turtleGraphicsPane.back(token.value);
token = scanner.getToken();
} else {
error("BACK requires distance");
return;
}
break;
case LogoToken.LEFT:
token = scanner.getToken();
if (token.kind == LogoToken.FLOAT || token.kind == LogoToken.INTEGER) {
turtleGraphicsPane.left(token.value);
token = scanner.getToken();
} else {
error("LEFT requires turn angle");
return;
}
break;
case LogoToken.RIGHT:
token = scanner.getToken();
if (token.kind == LogoToken.FLOAT || token.kind == LogoToken.INTEGER) {
turtleGraphicsPane.right(token.value);
token = scanner.getToken();
} else {
error("RIGHT requires turn angle");
return;
}
break;
case LogoToken.PENUP:
turtleGraphicsPane.penUp();
token = scanner.getToken();
break;
case LogoToken.PENDOWN:
turtleGraphicsPane.penDown();
token = scanner.getToken();
break;
case LogoToken.HIDETURTLE:
turtleGraphicsPane.hideTurtle();
token = scanner.getToken();
break;
case LogoToken.SHOWTURTLE:
turtleGraphicsPane.showTurtle();
token = scanner.getToken();
break;
case LogoToken.CLEARSCREEN:
turtleGraphicsPane.clearScreen();
token = scanner.getToken();
break;
case LogoToken.REPEAT:
token = scanner.getToken();
if (token.kind != LogoToken.INTEGER) {
error("REPEAT requires positive integer count");
return;
}
int count = token.intValue;
token = scanner.getToken();
if (token.kind != '[') {
error("REPEAT requires block in []");
return;
}
final int blockStart = scanner.getPosition();
while (count-- > 0) {
scanner.setPosition(blockStart);
parseCommandBlock(nestLevel + 1);
}
token = scanner.getToken();
break;
case LogoToken.TO:
token = scanner.getToken();
if (token.kind != LogoToken.IDENTIFIER) {
error("TO requires name for new definition");
return;
}
commandName = token.lexeme;
if (dictionary.get(commandName) == null) {
message("Defining new command " + commandName);
} else {
message("Redefining command " + commandName);
}
code = scanner.getRestAsString();
dictionary.put(commandName, code);
token = scanner.getToken();
break;
case LogoToken.IDENTIFIER:
commandName = token.lexeme;
code = dictionary.get(commandName);
if (code == null) {
error("Undefined command " + commandName);
return;
}
final String savedCommand = scanner.getSourceString();
final int savedPosition = scanner.getPosition();
scanner.setSourceString(code);
parseCommandBlock(0);
scanner.setSourceString(savedCommand);
scanner.setPosition(savedPosition);
token = scanner.getToken();
break;
case LogoToken.SETPC:
token = scanner.getToken();
String s = token.lexeme;
final HColor newPenColor = s == null ? null : HColorSet.instance().getColorOrWhite(s);
if (newPenColor == null) {
error("Unrecognized color name");
return;
}
penColor = newPenColor;
turtleGraphicsPane.setPenColor(penColor);
token = scanner.getToken();
break;
case '[':
token = scanner.getToken();
break;
case ']':
if (nestLevel == 0) {
error("] without matching [");
token = scanner.getToken();
return;
}
return;
default:
error("Unrecognized symbol in input");
return;
}
}
}
public void doCommandLine(String commandLine) {
message(commandLine);
scanner.setSourceString(commandLine);
parseCommandBlock(0);
}
}

View File

@ -1,211 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2024, Arnaud Roques
*
* Project Info: https://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.logo;
import java.awt.Font;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.plantuml.klimt.UTranslate;
import net.sourceforge.plantuml.klimt.color.HColor;
import net.sourceforge.plantuml.klimt.color.HColorSet;
import net.sourceforge.plantuml.klimt.color.HColors;
import net.sourceforge.plantuml.klimt.creole.Display;
import net.sourceforge.plantuml.klimt.drawing.UGraphic;
import net.sourceforge.plantuml.klimt.font.FontConfiguration;
import net.sourceforge.plantuml.klimt.font.UFont;
import net.sourceforge.plantuml.klimt.geom.HorizontalAlignment;
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
import net.sourceforge.plantuml.klimt.shape.TextBlock;
import net.sourceforge.plantuml.klimt.shape.ULine;
import net.sourceforge.plantuml.klimt.shape.UPolygon;
import net.sourceforge.plantuml.klimt.sprite.SpriteContainerEmpty;
class TurtleGraphicsPane {
final private double width;
final private double height;
private double x;
private double y;
private double turtleDirection = 90;
private boolean penIsDown = true;
private boolean showTurtle = true;
private HColor penColor = HColors.BLACK;
private List<Rectangle2D.Double> lines = new ArrayList<Rectangle2D.Double>();
private List<HColor> colors = new ArrayList<>();
private String message;
public TurtleGraphicsPane(int width, int height) {
this.width = width;
this.height = height;
clearScreen();
}
public void clearScreen() {
x = width / 2;
y = -height / 2;
turtleDirection = 90;
lines.clear();
colors.clear();
}
private double dtor(double degrees) {
return degrees * Math.PI / 180.0;
}
private void drawTurtle(UGraphic ug) {
if (showTurtle == false) {
return;
}
final UPolygon poly = new UPolygon();
double size = 2;
double deltax = 4.5 * size;
poly.addPoint(0 * size - deltax, 0);
poly.addPoint(0 * size - deltax, -2 * size);
poly.addPoint(1 * size - deltax, -2 * size);
poly.addPoint(1 * size - deltax, -4 * size);
poly.addPoint(2 * size - deltax, -4 * size);
poly.addPoint(2 * size - deltax, -6 * size);
poly.addPoint(3 * size - deltax, -6 * size);
poly.addPoint(3 * size - deltax, -8 * size);
poly.addPoint(4 * size - deltax, -8 * size);
poly.addPoint(4 * size - deltax, -9 * size);
poly.addPoint(5 * size - deltax, -9 * size);
poly.addPoint(5 * size - deltax, -8 * size);
poly.addPoint(6 * size - deltax, -8 * size);
poly.addPoint(6 * size - deltax, -6 * size);
poly.addPoint(7 * size - deltax, -6 * size);
poly.addPoint(7 * size - deltax, -4 * size);
poly.addPoint(8 * size - deltax, -4 * size);
poly.addPoint(8 * size - deltax, -2 * size);
poly.addPoint(9 * size - deltax, -2 * size);
poly.addPoint(9 * size - deltax, 0);
poly.addPoint(0 * size - deltax, 0);
final double angle = -dtor(turtleDirection - 90);
poly.rotate(angle);
// ug.setAntiAliasing(false);
final HColorSet htmlColorSet = HColorSet.instance();
final HColor turtleColor1 = htmlColorSet.getColorOrWhite("OliveDrab");
final HColor turtleColor2 = htmlColorSet.getColorOrWhite("MediumSpringGreen");
ug.apply(turtleColor1).apply(turtleColor2.bg()).apply(new UTranslate(x, -y)).draw(poly);
// ug.setAntiAliasing(true);
}
public void showTurtle() {
showTurtle = true;
}
public void hideTurtle() {
showTurtle = false;
}
public void setPenColor(HColor newPenColor) {
penColor = newPenColor;
}
void addLine(double x1, double y1, double x2, double y2) {
lines.add(new Rectangle2D.Double(x1, y1, x2, y2));
colors.add(penColor);
}
public void forward(double distance) {
double angle = dtor(turtleDirection);
double newX = x + distance * Math.cos(angle);
double newY = y + distance * Math.sin(angle);
if (penIsDown) {
addLine(x, y, newX, newY);
x = newX;
y = newY;
} else {
x = newX;
y = newY;
}
}
public void back(double distance) {
forward(-distance);
}
public void left(double turnAngle) {
turtleDirection += turnAngle;
while (turtleDirection > 360) {
turtleDirection -= 360;
}
while (turtleDirection < 0) {
turtleDirection += 360;
}
}
public void right(double turnAngle) {
left(-turnAngle);
}
public void penUp() {
penIsDown = false;
}
public void penDown() {
penIsDown = true;
}
public void paint(UGraphic ug) {
int n = lines.size();
for (int i = 0; i < n; i++) {
final HColor color = colors.get(i);
final Rectangle2D.Double r = lines.get(i);
final ULine line = new ULine(r.width - r.x, -r.height + r.y);
ug.apply(color).apply(new UTranslate(r.x, -r.y)).draw(line);
}
drawTurtle(ug);
if (message != null) {
final FontConfiguration font = FontConfiguration.blackBlueTrue(UFont.build("", Font.PLAIN, 14));
final TextBlock text = Display.create(message).create(font, HorizontalAlignment.LEFT,
new SpriteContainerEmpty());
final XDimension2D dim = text.calculateDimension(ug.getStringBounder());
final double textHeight = dim.getHeight();
text.drawU(ug.apply(UTranslate.dy((height - textHeight))));
}
}
public void message(String messageText) {
this.message = messageText;
}
}

View File

@ -1,493 +0,0 @@
/*
* MJPEGGenerator.java
*
* Created on April 17, 2006, 11:48 PM
*
* To change this template, choose Tools | Options and locate the template under
* the Source Creation and Management node. Right-click the template and choose
* Open. You can then make changes to the template in the Source Editor.
*/
package net.sourceforge.plantuml.mjpeg;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import net.sourceforge.plantuml.security.SFile;
import net.sourceforge.plantuml.security.SImageIO;
/**
*
* @author monceaux
*/
public class MJPEGGenerator {
// ::remove folder when __HAXE__
// ::remove folder when __CORE__
/*
* Info needed for MJPEG AVI
*
* - size of file minus "RIFF & 4 byte file size"
*
*/
int width = 0;
int height = 0;
double framerate = 0;
int numFrames = 0;
SFile aviFile = null;
FileOutputStream aviOutput = null;
FileChannel aviChannel = null;
long riffOffset = 0;
long aviMovieOffset = 0;
AVIIndexList indexlist = null;
/** Creates a new instance of MJPEGGenerator */
public MJPEGGenerator(SFile aviFile, int width, int height, double framerate, int numFrames) throws IOException {
this.aviFile = aviFile;
this.width = width;
this.height = height;
this.framerate = framerate;
this.numFrames = numFrames;
aviOutput = aviFile.createFileOutputStream();
aviChannel = aviOutput.getChannel();
RIFFHeader rh = new RIFFHeader();
aviOutput.write(rh.toBytes());
aviOutput.write(new AVIMainHeader().toBytes());
aviOutput.write(new AVIStreamList().toBytes());
aviOutput.write(new AVIStreamHeader().toBytes());
aviOutput.write(new AVIStreamFormat().toBytes());
aviOutput.write(new AVIJunk().toBytes());
aviMovieOffset = aviChannel.position();
aviOutput.write(new AVIMovieList().toBytes());
indexlist = new AVIIndexList();
}
public void addImage(Image image) throws IOException {
byte[] fcc = new byte[] { '0', '0', 'd', 'b' };
byte[] imagedata = writeImageToBytes(image);
int useLength = imagedata.length;
long position = aviChannel.position();
int extra = (useLength + (int) position) % 4;
if (extra > 0)
useLength = useLength + extra;
indexlist.addAVIIndex((int) position, useLength);
aviOutput.write(fcc);
aviOutput.write(intBytes(swapInt(useLength)));
aviOutput.write(imagedata);
if (extra > 0) {
for (int i = 0; i < extra; i++)
aviOutput.write(0);
}
imagedata = null;
}
public void finishAVI() throws IOException {
byte[] indexlistBytes = indexlist.toBytes();
aviOutput.write(indexlistBytes);
aviOutput.close();
long size = aviFile.length();
RandomAccessFile raf = new RandomAccessFile(aviFile.conv(), "rw");
raf.seek(4);
raf.write(intBytes(swapInt((int) size - 8)));
raf.seek(aviMovieOffset + 4);
raf.write(intBytes(swapInt((int) (size - 8 - aviMovieOffset - indexlistBytes.length))));
raf.close();
}
// public void writeAVI(File file) throws Exception
// {
// OutputStream os = SecurityUtils.FileOutputStream(file);
//
// // RIFFHeader
// // AVIMainHeader
// // AVIStreamList
// // AVIStreamHeader
// // AVIStreamFormat
// // write 00db and image bytes...
// }
public static int swapInt(int v) {
return (v >>> 24) | (v << 24) | ((v << 8) & 0x00FF0000) | ((v >> 8) & 0x0000FF00);
}
public static short swapShort(short v) {
return (short) ((v >>> 8) | (v << 8));
}
public static byte[] intBytes(int i) {
byte[] b = new byte[4];
b[0] = (byte) (i >>> 24);
b[1] = (byte) ((i >>> 16) & 0x000000FF);
b[2] = (byte) ((i >>> 8) & 0x000000FF);
b[3] = (byte) (i & 0x000000FF);
return b;
}
public static byte[] shortBytes(short i) {
byte[] b = new byte[2];
b[0] = (byte) (i >>> 8);
b[1] = (byte) (i & 0x000000FF);
return b;
}
private class RIFFHeader {
public byte[] fcc = new byte[] { 'R', 'I', 'F', 'F' };
public int fileSize = 0;
public byte[] fcc2 = new byte[] { 'A', 'V', 'I', ' ' };
public byte[] fcc3 = new byte[] { 'L', 'I', 'S', 'T' };
public int listSize = 200;
public byte[] fcc4 = new byte[] { 'h', 'd', 'r', 'l' };
public RIFFHeader() {
}
public byte[] toBytes() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(fileSize)));
baos.write(fcc2);
baos.write(fcc3);
baos.write(intBytes(swapInt(listSize)));
baos.write(fcc4);
baos.close();
return baos.toByteArray();
}
}
private class AVIMainHeader {
/*
*
* FOURCC fcc; DWORD cb; DWORD dwMicroSecPerFrame; DWORD dwMaxBytesPerSec; DWORD
* dwPaddingGranularity; DWORD dwFlags; DWORD dwTotalFrames; DWORD
* dwInitialFrames; DWORD dwStreams; DWORD dwSuggestedBufferSize; DWORD dwWidth;
* DWORD dwHeight; DWORD dwReserved[4];
*/
public byte[] fcc = new byte[] { 'a', 'v', 'i', 'h' };
public int cb = 56;
public int dwMicroSecPerFrame = 0; // (1 / frames per sec) * 1,000,000
public int dwMaxBytesPerSec = 10000000;
public int dwPaddingGranularity = 0;
public int dwFlags = 65552;
public int dwTotalFrames = 0; // replace with correct value
public int dwInitialFrames = 0;
public int dwStreams = 1;
public int dwSuggestedBufferSize = 0;
public int dwWidth = 0; // replace with correct value
public int dwHeight = 0; // replace with correct value
public int[] dwReserved = new int[4];
public AVIMainHeader() {
dwMicroSecPerFrame = (int) ((1.0 / framerate) * 1000000.0);
dwWidth = width;
dwHeight = height;
dwTotalFrames = numFrames;
}
public byte[] toBytes() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(cb)));
baos.write(intBytes(swapInt(dwMicroSecPerFrame)));
baos.write(intBytes(swapInt(dwMaxBytesPerSec)));
baos.write(intBytes(swapInt(dwPaddingGranularity)));
baos.write(intBytes(swapInt(dwFlags)));
baos.write(intBytes(swapInt(dwTotalFrames)));
baos.write(intBytes(swapInt(dwInitialFrames)));
baos.write(intBytes(swapInt(dwStreams)));
baos.write(intBytes(swapInt(dwSuggestedBufferSize)));
baos.write(intBytes(swapInt(dwWidth)));
baos.write(intBytes(swapInt(dwHeight)));
baos.write(intBytes(swapInt(dwReserved[0])));
baos.write(intBytes(swapInt(dwReserved[1])));
baos.write(intBytes(swapInt(dwReserved[2])));
baos.write(intBytes(swapInt(dwReserved[3])));
baos.close();
return baos.toByteArray();
}
}
private class AVIStreamList {
public byte[] fcc = new byte[] { 'L', 'I', 'S', 'T' };
public int size = 124;
public byte[] fcc2 = new byte[] { 's', 't', 'r', 'l' };
public AVIStreamList() {
}
public byte[] toBytes() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(size)));
baos.write(fcc2);
baos.close();
return baos.toByteArray();
}
}
private class AVIStreamHeader {
/*
* FOURCC fcc; DWORD cb; FOURCC fccType; FOURCC fccHandler; DWORD dwFlags; WORD
* wPriority; WORD wLanguage; DWORD dwInitialFrames; DWORD dwScale; DWORD
* dwRate; DWORD dwStart; DWORD dwLength; DWORD dwSuggestedBufferSize; DWORD
* dwQuality; DWORD dwSampleSize; struct { short int left; short int top; short
* int right; short int bottom; } rcFrame;
*/
public byte[] fcc = new byte[] { 's', 't', 'r', 'h' };
public int cb = 64;
public byte[] fccType = new byte[] { 'v', 'i', 'd', 's' };
public byte[] fccHandler = new byte[] { 'M', 'J', 'P', 'G' };
public int dwFlags = 0;
public short wPriority = 0;
public short wLanguage = 0;
public int dwInitialFrames = 0;
public int dwScale = 0; // microseconds per frame
public int dwRate = 1000000; // dwRate / dwScale = frame rate
public int dwStart = 0;
public int dwLength = 0; // num frames
public int dwSuggestedBufferSize = 0;
public int dwQuality = -1;
public int dwSampleSize = 0;
public int left = 0;
public int top = 0;
public int right = 0;
public int bottom = 0;
public AVIStreamHeader() {
dwScale = (int) ((1.0 / framerate) * 1000000.0);
dwLength = numFrames;
}
public byte[] toBytes() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(cb)));
baos.write(fccType);
baos.write(fccHandler);
baos.write(intBytes(swapInt(dwFlags)));
baos.write(shortBytes(swapShort(wPriority)));
baos.write(shortBytes(swapShort(wLanguage)));
baos.write(intBytes(swapInt(dwInitialFrames)));
baos.write(intBytes(swapInt(dwScale)));
baos.write(intBytes(swapInt(dwRate)));
baos.write(intBytes(swapInt(dwStart)));
baos.write(intBytes(swapInt(dwLength)));
baos.write(intBytes(swapInt(dwSuggestedBufferSize)));
baos.write(intBytes(swapInt(dwQuality)));
baos.write(intBytes(swapInt(dwSampleSize)));
baos.write(intBytes(swapInt(left)));
baos.write(intBytes(swapInt(top)));
baos.write(intBytes(swapInt(right)));
baos.write(intBytes(swapInt(bottom)));
baos.close();
return baos.toByteArray();
}
}
private class AVIStreamFormat {
/*
* FOURCC fcc; DWORD cb; DWORD biSize; LONG biWidth; LONG biHeight; WORD
* biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG
* biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant;
*/
public byte[] fcc = new byte[] { 's', 't', 'r', 'f' };
public int cb = 40;
public int biSize = 40; // same as cb
public int biWidth = 0;
public int biHeight = 0;
public short biPlanes = 1;
public short biBitCount = 24;
public byte[] biCompression = new byte[] { 'M', 'J', 'P', 'G' };
public int biSizeImage = 0; // width x height in pixels
public int biXPelsPerMeter = 0;
public int biYPelsPerMeter = 0;
public int biClrUsed = 0;
public int biClrImportant = 0;
public AVIStreamFormat() {
biWidth = width;
biHeight = height;
biSizeImage = width * height;
}
public byte[] toBytes() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(cb)));
baos.write(intBytes(swapInt(biSize)));
baos.write(intBytes(swapInt(biWidth)));
baos.write(intBytes(swapInt(biHeight)));
baos.write(shortBytes(swapShort(biPlanes)));
baos.write(shortBytes(swapShort(biBitCount)));
baos.write(biCompression);
baos.write(intBytes(swapInt(biSizeImage)));
baos.write(intBytes(swapInt(biXPelsPerMeter)));
baos.write(intBytes(swapInt(biYPelsPerMeter)));
baos.write(intBytes(swapInt(biClrUsed)));
baos.write(intBytes(swapInt(biClrImportant)));
baos.close();
return baos.toByteArray();
}
}
private class AVIMovieList {
public byte[] fcc = new byte[] { 'L', 'I', 'S', 'T' };
public int listSize = 0;
public byte[] fcc2 = new byte[] { 'm', 'o', 'v', 'i' };
// 00db size jpg image data ...
public AVIMovieList() {
}
public byte[] toBytes() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(listSize)));
baos.write(fcc2);
baos.close();
return baos.toByteArray();
}
}
private class AVIIndexList {
public byte[] fcc = new byte[] { 'i', 'd', 'x', '1' };
public int cb = 0;
public ArrayList ind = new ArrayList();
public AVIIndexList() {
}
public void addAVIIndex(AVIIndex ai) {
ind.add(ai);
}
public void addAVIIndex(int dwOffset, int dwSize) {
ind.add(new AVIIndex(dwOffset, dwSize));
}
public byte[] toBytes() throws IOException {
cb = 16 * ind.size();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(cb)));
for (int i = 0; i < ind.size(); i++) {
AVIIndex in = (AVIIndex) ind.get(i);
baos.write(in.toBytes());
}
baos.close();
return baos.toByteArray();
}
}
private class AVIIndex {
public byte[] fcc = new byte[] { '0', '0', 'd', 'b' };
public int dwFlags = 16;
public int dwOffset = 0;
public int dwSize = 0;
public AVIIndex(int dwOffset, int dwSize) {
this.dwOffset = dwOffset;
this.dwSize = dwSize;
}
public byte[] toBytes() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(dwFlags)));
baos.write(intBytes(swapInt(dwOffset)));
baos.write(intBytes(swapInt(dwSize)));
baos.close();
return baos.toByteArray();
}
}
private class AVIJunk {
public byte[] fcc = new byte[] { 'J', 'U', 'N', 'K' };
public int size = 1808;
public byte[] data = new byte[size];
public AVIJunk() {
Arrays.fill(data, (byte) 0);
}
public byte[] toBytes() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(fcc);
baos.write(intBytes(swapInt(size)));
baos.write(data);
baos.close();
return baos.toByteArray();
}
}
private byte[] writeImageToBytes(Image image) throws IOException {
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Graphics2D g = bi.createGraphics();
g.drawImage(image, 0, 0, width, height, null);
SImageIO.write(bi, "jpg", baos);
baos.close();
bi = null;
g = null;
return baos.toByteArray();
}
// public static void main(String[] args) throws Exception {
// double framerate = 12.0;
// double transitionDuration = 1; // seconds
// double slideDuration = 3; // seconds
//
// File photoDir = SecurityUtils.file(args[0]);
// File[] files = photoDir.listFiles(new FilenameFilter() {
// public boolean accept(java.io.File dir, String name) {
// if (StringUtils.goLowerCase(name).endsWith("jpg"))
// return true;
// return false;
// }
// });
//
// int numFrames = (int) (files.length * framerate * (slideDuration + transitionDuration)
// + (transitionDuration * framerate));
// MJPEGGenerator m = new MJPEGGenerator(SecurityUtils.file(args[1]), 640, 480, framerate, numFrames);
// for (int i = 0; i < files.length; i++) {
// System.out.println("processing file " + i);
// ImageIcon ii = new ImageIcon(files[i].getCanonicalPath());
// m.addImage(ii.getImage());
// }
// m.finishAVI();
// }
}

View File

@ -35,23 +35,20 @@
*/
package net.sourceforge.plantuml.png;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.io.OutputStream;
import net.sourceforge.plantuml.klimt.color.ColorMapper;
import net.sourceforge.plantuml.quantization.Quantizer;
import net.sourceforge.plantuml.security.SFile;
import net.sourceforge.plantuml.security.SImageIO;
import net.sourceforge.plantuml.utils.Log;
public class PngIO {
// ::remove folder when __HAXE__
// ::remove folder when __HAXE__
// ::comment when __CORE__
private static final String copyleft = "Generated by https://plantuml.com";
public static boolean USE_QUANTIZATION = false;
public static void write(RenderedImage image, ColorMapper mapper, SFile file, String metadata, int dpi)
throws IOException {
@ -76,9 +73,6 @@ public class PngIO {
String debugData) throws IOException {
// ::comment when __CORE__
if (USE_QUANTIZATION)
image = Quantizer.quantizeNow(mapper, (BufferedImage) image);
if (metadata == null)
// ::done
SImageIO.write(image, "png", os);

View File

@ -1,78 +0,0 @@
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sourceforge.plantuml.quantization;
import java.util.Comparator;
import java.util.WeakHashMap;
/**
* Provides a stable ordering of objects, such that:
*
* <ul>
* <li>compare(a, b) == 0 iff a == b</li>
* <li>sign(compare(a, b)) == -sign(compare(b, a))</li>
* </ul>
*
* <p>
* Similar to Guava's {code Ordering.arbitrary()}.
*/
final class ArbitraryComparator implements Comparator<Object> {
public static final ArbitraryComparator INSTANCE = new ArbitraryComparator();
/**
* If we have no other way to order two objects in a stable manner, we will
* register both in this map and order them according to their associated
* values. The map's values are just integers corresponding to the order in
* which objects were added.
*/
private static final WeakHashMap<Object, Integer> objectIds = new WeakHashMap<>();
private ArbitraryComparator() {
}
@Override
public int compare(Object a, Object b) {
if (a == b)
return 0;
if (a == null)
return -1;
if (b == null)
return 1;
int identityHashCodeDifference = System.identityHashCode(a) - System.identityHashCode(b);
if (identityHashCodeDifference != 0) {
return identityHashCodeDifference;
}
// We have an identityHashCode collision.
return getObjectId(a) - getObjectId(b);
}
/**
* Get the ID of an object, adding it to the ID map if it isn't already
* registered.
*/
private static int getObjectId(Object object) {
synchronized (objectIds) {
Integer id = objectIds.get(object);
if (id == null) {
id = objectIds.size();
objectIds.put(object, id);
}
return id;
}
}
}

View File

@ -1,19 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.util.Set;
public interface ColorQuantizer {
/**
* Quantize the given set of colors, returning a set no larger than
* {@code maxColors}.
*
* <p>
* The intent is to pick a set of colors which are representative of the
* original color set, but no specific guarantees are made.
*
* @param originalColors the colors in the original image
* @param maxColorCount the maximum number of colors to allow
* @return a quantized collection of colors no larger than {@code maxColors}
*/
public Set<QColor> quantize(Multiset<QColor> originalColors, int maxColorCount);
}

View File

@ -1,16 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.util.Set;
public interface Ditherer {
// ::remove folder when __HAXE__
/**
* Dither the given image, producing a new image which only contains colors from
* the given color set.
*
* @param image the original, unquantized image
* @param newColors the quantized set of colors to be used in the new image
* @return a new image containing only of colors from {@code newColors}
*/
public QImage dither(QImage image, Set<QColor> newColors);
}

View File

@ -1,53 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.util.Set;
public final class FloydSteinbergDitherer implements Ditherer {
public static final FloydSteinbergDitherer INSTANCE = new FloydSteinbergDitherer();
private static final ErrorComponent[] ERROR_DISTRIBUTION = { new ErrorComponent(1, 0, 7.0 / 16.0),
new ErrorComponent(-1, 1, 3.0 / 16.0), new ErrorComponent(0, 1, 5.0 / 16.0),
new ErrorComponent(1, 1, 1.0 / 16.0) };
private FloydSteinbergDitherer() {
}
@Override
public QImage dither(QImage image, Set<QColor> newColors) {
final int width = image.getWidth();
final int height = image.getHeight();
QColor[][] colors = new QColor[height][width];
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
colors[y][x] = image.getColor(x, y);
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x) {
final QColor originalColor = colors[y][x];
final QColor replacementColor = originalColor.getNearestColor(newColors);
colors[y][x] = replacementColor;
final QColor error = originalColor.minus(replacementColor);
for (ErrorComponent component : ERROR_DISTRIBUTION) {
int siblingX = x + component.deltaX, siblingY = y + component.deltaY;
if (siblingX >= 0 && siblingY >= 0 && siblingX < width && siblingY < height) {
QColor errorComponent = error.scaled(component.errorFraction);
colors[siblingY][siblingX] = colors[siblingY][siblingX].plus(errorComponent);
}
}
}
return QImage.fromColors(colors);
}
private static final class ErrorComponent {
final int deltaX, deltaY;
final double errorFraction;
ErrorComponent(int deltaX, int deltaY, double errorFraction) {
this.deltaX = deltaX;
this.deltaY = deltaY;
this.errorFraction = errorFraction;
}
}
}

View File

@ -1,133 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
public final class HashMultiset<E> extends AbstractCollection<E> implements Multiset<E> {
private final Map<E, Count> elementCounts = new HashMap<>();
private int size;
public HashMultiset() {
}
public HashMultiset(Collection<E> source) {
addAll(source);
}
@Override
public void add(E element, int n) {
Count count = elementCounts.get(element);
if (count != null)
count.value += n;
else
elementCounts.put(element, new Count(n));
size += n;
}
@Override
public boolean add(E element) {
add(element, 1);
return true;
}
@Override
public int remove(Object element, int n) {
Count count = elementCounts.get(element);
if (count == null)
return 0;
if (n < count.value) {
count.value -= n;
size -= n;
return n;
}
elementCounts.remove(element);
size -= count.value;
return count.value;
}
@Override
public boolean remove(Object element) {
return remove(element, 1) > 0;
}
@Override
public Iterator<E> iterator() {
return new HashMultisetIterator();
}
@Override
public int size() {
return size;
}
@Override
public int count(Object element) {
Count countOrNull = elementCounts.get(element);
return countOrNull != null ? countOrNull.value : 0;
}
@Override
public Set<E> getDistinctElements() {
return elementCounts.keySet();
}
private final class HashMultisetIterator implements Iterator<E> {
final private Iterator<Map.Entry<E, Count>> distinctElementIterator;
private E currentElement;
private int currentCount;
private boolean currentElementRemoved;
HashMultisetIterator() {
this.distinctElementIterator = elementCounts.entrySet().iterator();
this.currentCount = 0;
}
@Override
public boolean hasNext() {
return currentCount > 0 || distinctElementIterator.hasNext();
}
@Override
public E next() {
if (hasNext() == false)
throw new NoSuchElementException("iterator has been exhausted");
if (currentCount == 0) {
Map.Entry<E, Count> next = distinctElementIterator.next();
currentElement = next.getKey();
currentCount = next.getValue().value;
}
currentCount--;
currentElementRemoved = false;
return currentElement;
}
@Override
public void remove() {
if (currentElement == null)
throw new IllegalStateException("next() has not been called");
if (currentElementRemoved)
throw new IllegalStateException("remove() already called for current element");
HashMultiset.this.remove(currentElement);
}
}
private static final class Count {
private int value;
Count(int value) {
this.value = value;
}
}
}

View File

@ -1,76 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Uses k-means clustering for color quantization. This tends to yield good
* results, but convergence can be slow. It is not recommended for large images.
*/
public final class KMeansQuantizer implements ColorQuantizer {
public static final KMeansQuantizer INSTANCE = new KMeansQuantizer();
private KMeansQuantizer() {
}
@Override
public Set<QColor> quantize(Multiset<QColor> originalColors, int maxColorCount) {
Map<QColor, Multiset<QColor>> clustersByCentroid = new LinkedHashMap<>();
Set<QColor> centroidsToRecompute = getInitialCentroids(originalColors, maxColorCount);
for (QColor centroid : centroidsToRecompute)
clustersByCentroid.put(centroid, new HashMultiset<QColor>());
for (QColor color : originalColors.getDistinctElements()) {
final int count = originalColors.count(color);
clustersByCentroid.get(color.getNearestColor(centroidsToRecompute)).add(color, count);
}
while (centroidsToRecompute.isEmpty() == false) {
recomputeCentroids(clustersByCentroid, centroidsToRecompute);
centroidsToRecompute.clear();
Set<QColor> allCentroids = clustersByCentroid.keySet();
for (QColor centroid : clustersByCentroid.keySet()) {
Multiset<QColor> cluster = clustersByCentroid.get(centroid);
for (QColor color : new ArrayList<>(cluster.getDistinctElements())) {
QColor newCentroid = color.getNearestColor(allCentroids);
if (newCentroid != centroid) {
final int count = cluster.count(color);
final Multiset<QColor> newCluster = clustersByCentroid.get(newCentroid);
cluster.remove(color, count);
newCluster.add(color, count);
centroidsToRecompute.add(centroid);
centroidsToRecompute.add(newCentroid);
}
}
}
}
return clustersByCentroid.keySet();
}
private static void recomputeCentroids(Map<QColor, Multiset<QColor>> clustersByCentroid,
Set<QColor> centroidsToRecompute) {
for (QColor oldCentroid : centroidsToRecompute) {
final Multiset<QColor> cluster = clustersByCentroid.get(oldCentroid);
final QColor newCentroid = QColor.getCentroid(cluster);
clustersByCentroid.remove(oldCentroid);
clustersByCentroid.put(newCentroid, cluster);
}
}
private static Set<QColor> getInitialCentroids(Multiset<QColor> originalColors, int maxColorCount) {
// We use the Forgy initialization method: choose random colors as initial
// cluster centroids.
final List<QColor> colorList = new ArrayList<>(originalColors.getDistinctElements());
Collections.shuffle(colorList);
return new HashSet<>(colorList.subList(0, maxColorCount));
}
}

View File

@ -1,136 +0,0 @@
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sourceforge.plantuml.quantization;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/**
* Implements median cut quantization.
*
* <p>
* The algorithm works as follows:
*
* <ul>
* <li>Begin with one cluster containing all the original colors.</li>
* <li>Find the cluster containing the greatest spread along a single color
* component (red, green or blue).</li>
* <li>Find the median of that color component among colors in the cluster.</li>
* <li>Split the cluster into two halves, using that median as a threshold.</li>
* <li>Repeat this process until the desired number of clusters is reached.</li>
* </ul>
*/
public final class MedianCutQuantizer implements ColorQuantizer {
public static final MedianCutQuantizer INSTANCE = new MedianCutQuantizer();
private MedianCutQuantizer() {
}
@Override
public Set<QColor> quantize(Multiset<QColor> originalColors, int maxColorCount) {
TreeSet<Cluster> clusters = new TreeSet<>(new ClusterSpreadComparator());
clusters.add(new Cluster(originalColors));
while (clusters.size() < maxColorCount) {
Cluster clusterWithLargestSpread = clusters.pollFirst();
clusters.addAll(clusterWithLargestSpread.split());
}
Set<QColor> clusterCentroids = new HashSet<>();
for (Cluster cluster : clusters) {
clusterCentroids.add(QColor.getCentroid(cluster.colors));
}
return clusterCentroids;
}
private static final class Cluster {
final Multiset<QColor> colors;
double largestSpread;
int componentWithLargestSpread;
Cluster(Multiset<QColor> colors) {
this.colors = colors;
this.largestSpread = -1;
for (int component = 0; component < 3; ++component) {
double componentSpread = getComponentSpread(component);
if (componentSpread > largestSpread) {
largestSpread = componentSpread;
componentWithLargestSpread = component;
}
}
}
double getComponentSpread(int component) {
double min = Double.POSITIVE_INFINITY;
double max = Double.NEGATIVE_INFINITY;
for (QColor color : colors) {
min = Math.min(min, color.getComponent(component));
max = Math.max(max, color.getComponent(component));
}
return max - min;
}
Collection<Cluster> split() {
List<QColor> orderedColors = new ArrayList<>(colors);
Collections.sort(orderedColors, new ColorComponentComparator(componentWithLargestSpread));
int medianIndex = orderedColors.size() / 2;
return Arrays.asList(new Cluster(new HashMultiset<>(orderedColors.subList(0, medianIndex))),
new Cluster(new HashMultiset<>(orderedColors.subList(medianIndex, orderedColors.size()))));
}
}
/**
* Orders clusters according to their maximum spread, in descending order.
*/
static final class ClusterSpreadComparator implements Comparator<Cluster> {
@Override
public int compare(Cluster a, Cluster b) {
double spreadDifference = b.largestSpread - a.largestSpread;
if (spreadDifference == 0) {
return ArbitraryComparator.INSTANCE.compare(a, b);
}
return (int) Math.signum(spreadDifference);
}
}
/**
* Orders colors according to the value of one particular component, in
* ascending order.
*/
static final class ColorComponentComparator implements Comparator<QColor> {
final int component;
ColorComponentComparator(int component) {
this.component = component;
}
@Override
public int compare(QColor a, QColor b) {
double componentDifference = a.getComponent(component) - b.getComponent(component);
if (componentDifference == 0) {
return ArbitraryComparator.INSTANCE.compare(a, b);
}
return (int) Math.signum(componentDifference);
}
}
}

View File

@ -1,33 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.util.Collection;
import java.util.Set;
/**
* A collection which permits duplicates, and provides methods adding/removing
* several counts of an element.
*
* @param <E> the element type
*/
public interface Multiset<E> extends Collection<E> {
/**
* Add n counts of an element.
*
* @param element the element to add
* @param n how many to add
*/
public void add(E element, int n);
/**
* Remove up to n counts of an element.
*
* @param element the element the remove
* @param n how many to remove
* @return the number of elements removed
*/
public int remove(Object element, int n);
public int count(Object element);
public Set<E> getDistinctElements();
}

View File

@ -1,143 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.util.Collection;
import net.sourceforge.plantuml.klimt.color.ColorMapper;
/**
* An RGB representation of a color, which stores each component as a double in
* the range [0, 1]. Values outside of [0, 1] are permitted though, as this is
* convenient e.g. for representing color deltas.
*/
public final class QColor {
public static final QColor BLACK = new QColor(0, 0, 0);
public static final QColor WHITE = new QColor(1, 1, 1);
public static final QColor RED = new QColor(1, 0, 0);
public static final QColor GREEN = new QColor(0, 1, 0);
public static final QColor BLUE = new QColor(0, 0, 1);
private final double red;
private final double green;
private final double blue;
public QColor(double red, double green, double blue) {
this.red = red;
this.green = green;
this.blue = blue;
}
public static QColor fromArgbInt(ColorMapper mapper, int rgb) {
final double alpha = (rgb >>> 24 & 0xFF) / 255.0;
double red = (rgb >>> 16 & 0xFF) / 255.0;
double green = (rgb >>> 8 & 0xFF) / 255.0;
double blue = (rgb & 0xFF) / 255.0;
if (mapper == ColorMapper.DARK_MODE) {
red = alpha * red;
green = alpha * green;
blue = alpha * blue;
} else {
red = 1 - alpha * (1 - red);
green = 1 - alpha * (1 - green);
blue = 1 - alpha * (1 - blue);
}
return new QColor(red, green, blue);
}
public static QColor fromRgbInt(int rgb) {
final double red = (rgb >>> 16 & 0xFF) / 255.0;
final double green = (rgb >>> 8 & 0xFF) / 255.0;
final double blue = (rgb & 0xFF) / 255.0;
return new QColor(red, green, blue);
}
public static QColor getCentroid(Multiset<QColor> colors) {
QColor sum = QColor.BLACK;
for (QColor color : colors.getDistinctElements()) {
int weight = colors.count(color);
sum = sum.plus(color.scaled(weight));
}
return sum.scaled(1.0 / colors.size());
}
public double getComponent(int index) {
switch (index) {
case 0:
return red;
case 1:
return green;
case 2:
return blue;
default:
throw new IllegalArgumentException("Unexpected component index: " + index);
}
}
public QColor scaled(double s) {
return new QColor(s * red, s * green, s * blue);
}
public QColor plus(QColor that) {
return new QColor(this.red + that.red, this.green + that.green, this.blue + that.blue);
}
public QColor minus(QColor that) {
return new QColor(this.red - that.red, this.green - that.green, this.blue - that.blue);
}
public double getEuclideanDistanceTo(QColor that) {
final QColor d = this.minus(that);
final double sumOfSquares = d.red * d.red + d.green * d.green + d.blue * d.blue;
return Math.sqrt(sumOfSquares);
}
/**
* Find this color's nearest neighbor, based on Euclidean distance, among some
* set of colors.
*/
public QColor getNearestColor(Collection<QColor> colors) {
QColor nearestCentroid = null;
double nearestCentroidDistance = Double.POSITIVE_INFINITY;
for (QColor color : colors) {
final double distance = getEuclideanDistanceTo(color);
if (distance < nearestCentroidDistance) {
nearestCentroid = color;
nearestCentroidDistance = distance;
}
}
return nearestCentroid;
}
public int getRgbInt() {
final int redComponent = (int) (red * 255);
final int greenComponent = (int) (green * 255);
final int blueComponent = (int) (blue * 255);
return redComponent << 16 | greenComponent << 8 | blueComponent;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof QColor))
return false;
final QColor that = (QColor) o;
return this.red == that.red && this.green == that.green && this.blue == that.blue;
}
@Override
public int hashCode() {
int result;
long temp;
temp = Double.doubleToLongBits(red);
result = (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(green);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(blue);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public String toString() {
return String.format("Color[%f, %f, %f]", red, green, blue);
}
}

View File

@ -1,92 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.awt.image.BufferedImage;
import net.sourceforge.plantuml.klimt.color.ColorMapper;
/**
* An immutable grid of pixel colors.
*/
public final class QImage {
/**
* The first index corresponds to the row, while the second index corresponds
* the column.
*/
private final QColor[][] colors;
private QImage(QColor[][] colors) {
this.colors = colors;
}
public static QImage fromBufferedImage(ColorMapper mapper, BufferedImage img) {
final int height = img.getHeight();
final int width = img.getWidth();
final QColor[][] colors = new QColor[height][width];
if (img.getType() == BufferedImage.TYPE_INT_ARGB) {
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
colors[y][x] = QColor.fromArgbInt(mapper, img.getRGB(x, y));
} else if (img.getType() == BufferedImage.TYPE_INT_RGB) {
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
colors[y][x] = QColor.fromRgbInt(img.getRGB(x, y));
} else {
throw new IllegalArgumentException();
}
return new QImage(colors);
}
public static QImage fromColors(QColor[][] colors) {
return new QImage(colors);
}
public QColor getColor(int x, int y) {
return colors[y][x];
}
public QColor getColor(int index) {
return colors[index / getWidth()][index % getWidth()];
}
Multiset<QColor> getColors() {
final Multiset<QColor> colorCounts = new HashMultiset<>();
for (int i = 0; i < getNumPixels(); ++i) {
final QColor color = getColor(i);
colorCounts.add(color);
}
return colorCounts;
}
public int getWidth() {
return colors[0].length;
}
public int getHeight() {
return colors.length;
}
public int getNumPixels() {
return getWidth() * getHeight();
}
public BufferedImage toBufferedImage() {
final BufferedImage result = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
for (int i = 0; i < result.getWidth(); i++)
for (int j = 0; j < result.getHeight(); j++)
result.setRGB(i, j, colors[j][i].getRgbInt());
return result;
}
public BufferedImage toBufferedImageKeepTransparency(BufferedImage orig) {
final BufferedImage result = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
for (int i = 0; i < result.getWidth(); i++)
for (int j = 0; j < result.getHeight(); j++) {
if ((orig.getRGB(i, j)) != 0x00000000)
result.setRGB(i, j, colors[j][i].getRgbInt() | 0xFF000000);
}
return result;
}
}

View File

@ -1,38 +0,0 @@
package net.sourceforge.plantuml.quantization;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Set;
import net.sourceforge.plantuml.klimt.color.ColorMapper;
public final class Quantizer {
// ::remove folder when __CORE__
private static final int MAX_COLOR_COUNT = 256;
private static QImage quantizeNow(QImage image) throws IOException {
Multiset<QColor> originalColors = image.getColors();
Set<QColor> distinctColors = originalColors.getDistinctElements();
if (distinctColors.size() > MAX_COLOR_COUNT) {
// distinctColors = KMeansQuantizer.INSTANCE.quantize(originalColors,
// MAX_COLOR_COUNT);
distinctColors = MedianCutQuantizer.INSTANCE.quantize(originalColors, MAX_COLOR_COUNT);
image = FloydSteinbergDitherer.INSTANCE.dither(image, distinctColors);
}
return image;
}
public static BufferedImage quantizeNow(ColorMapper mapper, BufferedImage orig) throws IOException {
final QImage raw = QImage.fromBufferedImage(mapper, orig);
final QImage result = quantizeNow(raw);
if (orig.getType() == BufferedImage.TYPE_INT_RGB)
return result.toBufferedImage();
else if (orig.getType() == BufferedImage.TYPE_INT_ARGB)
return result.toBufferedImageKeepTransparency(orig);
else
throw new IllegalArgumentException();
}
}

View File

@ -68,6 +68,8 @@ import net.sourceforge.plantuml.svek.HeaderLayout;
import net.sourceforge.plantuml.svek.ShapeType;
import net.sourceforge.plantuml.text.Guillemet;
import java.util.List;
public class EntityImageClassHeader extends AbstractEntityImage {
final private HeaderLayout headerLayout;
@ -112,11 +114,12 @@ public class EntityImageClassHeader extends AbstractEntityImage {
}
final TextBlock stereo;
List<String> stereotypeLabels = portionShower.getVisibleStereotypeLabels(entity);
if (stereotype == null || stereotype.getLabel(Guillemet.DOUBLE_COMPARATOR) == null
|| portionShower.showPortion(EntityPortion.STEREOTYPE, entity) == false)
|| stereotypeLabels.isEmpty())
stereo = null;
else
stereo = TextBlockUtils.withMargin(Display.create(stereotype.getLabels(skinParam.guillemet())).create(
stereo = TextBlockUtils.withMargin(Display.create(stereotypeLabels).create(
FontConfiguration.create(getSkinParam(), FontParam.CLASS_STEREOTYPE, stereotype),
HorizontalAlignment.CENTER, skinParam), 1, 0);

View File

@ -1,161 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2024, Arnaud Roques
*
* Project Info: https://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* https://plantuml.com/patreon (only 1$ per month!)
* https://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.syntax;
import java.util.Collections;
import java.util.List;
import net.sourceforge.plantuml.BlockUml;
import net.sourceforge.plantuml.ErrorUml;
import net.sourceforge.plantuml.OptionFlags;
import net.sourceforge.plantuml.SourceStringReader;
import net.sourceforge.plantuml.UmlDiagram;
import net.sourceforge.plantuml.annotation.DeadCode;
import net.sourceforge.plantuml.core.Diagram;
import net.sourceforge.plantuml.error.PSystemError;
import net.sourceforge.plantuml.preproc.Defines;
import net.sourceforge.plantuml.text.BackSlash;
import net.sourceforge.plantuml.utils.LineLocation;
import net.sourceforge.plantuml.utils.LineLocationImpl;
@DeadCode(comment = "used too much CPU")
public class SyntaxChecker {
// ::remove folder when __HAXE__
// ::remove file when __CORE__
public static SyntaxResult checkSyntax(List<String> source) {
final StringBuilder sb = new StringBuilder();
for (String s : source) {
sb.append(s);
sb.append(BackSlash.NEWLINE);
}
return checkSyntax(sb.toString());
}
public static SyntaxResult checkSyntax(String source) {
OptionFlags.getInstance().setQuiet(true);
final SyntaxResult result = new SyntaxResult();
if (source.startsWith("@startuml\n") == false) {
result.setError(true);
result.setLineLocation(new LineLocationImpl("", null).oneLineRead());
result.addErrorText("No @startuml/@enduml found");
return result;
}
if (source.endsWith("@enduml\n") == false && source.endsWith("@enduml") == false) {
result.setError(true);
result.setLineLocation(lastLineNumber2(source));
result.addErrorText("No @enduml found");
return result;
}
final SourceStringReader sourceStringReader = new SourceStringReader(Defines.createEmpty(), source,
Collections.<String>emptyList());
final List<BlockUml> blocks = sourceStringReader.getBlocks();
if (blocks.size() == 0) {
result.setError(true);
result.setLineLocation(lastLineNumber2(source));
result.addErrorText("No @enduml found");
return result;
}
final Diagram system = blocks.get(0).getDiagram();
result.setCmapData(system.hasUrl());
if (system instanceof UmlDiagram) {
result.setUmlDiagramType(((UmlDiagram) system).getUmlDiagramType());
result.setDescription(system.getDescription().getDescription());
} else if (system instanceof PSystemError) {
result.setError(true);
final PSystemError sys = (PSystemError) system;
result.setLineLocation(sys.getLineLocation());
result.setSystemError(sys);
for (ErrorUml er : sys.getErrorsUml())
result.addErrorText(er.getError());
} else {
result.setDescription(system.getDescription().getDescription());
}
return result;
}
public static SyntaxResult checkSyntaxFair(String source) {
final SyntaxResult result = new SyntaxResult();
final SourceStringReader sourceStringReader = new SourceStringReader(Defines.createEmpty(), source,
Collections.<String>emptyList());
final List<BlockUml> blocks = sourceStringReader.getBlocks();
if (blocks.size() == 0) {
result.setError(true);
result.setLineLocation(lastLineNumber2(source));
result.addErrorText("No @enduml found");
return result;
}
final Diagram system = blocks.get(0).getDiagram();
result.setCmapData(system.hasUrl());
if (system instanceof UmlDiagram) {
result.setUmlDiagramType(((UmlDiagram) system).getUmlDiagramType());
result.setDescription(system.getDescription().getDescription());
} else if (system instanceof PSystemError) {
result.setError(true);
final PSystemError sys = (PSystemError) system;
result.setLineLocation(sys.getLineLocation());
for (ErrorUml er : sys.getErrorsUml()) {
result.addErrorText(er.getError());
}
result.setSystemError(sys);
} else {
result.setDescription(system.getDescription().getDescription());
}
return result;
}
private static int lastLineNumber(String source) {
int result = 0;
for (int i = 0; i < source.length(); i++)
if (source.charAt(i) == '\n')
result++;
return result;
}
private static LineLocation lastLineNumber2(String source) {
LineLocationImpl result = new LineLocationImpl("", null).oneLineRead();
for (int i = 0; i < source.length(); i++)
if (source.charAt(i) == '\n')
result = result.oneLineRead();
return result;
}
}

View File

@ -55,14 +55,14 @@ public class StartUtils {
boolean inside = false;
for (int i = 0; i < s.length(); i++) {
final String tmp = s.substring(i, s.length());
if (startsWithSymbolAnd("start", tmp)) {
if (startsWithSymbolAnd("start", tmp))
return s.substring(0, i);
}
final String single = s.substring(i, i + 1);
if (inside) {
if (single.equals(">")) {
if (single.equals(">"))
inside = false;
}
continue;
}
if (single.equals("<")) {
@ -81,9 +81,9 @@ public class StartUtils {
public static boolean isArobaseStartDiagram(String s) {
final String s2 = StringUtils.trinNoTrace(s);
if (s2.startsWith("@") == false && s2.startsWith("\\") == false) {
if (s2.startsWith("@") == false && s2.startsWith("\\") == false)
return false;
}
return DiagramType.getTypeFromArobaseStart(s2) != DiagramType.UNKNOWN;
}
@ -97,9 +97,9 @@ public class StartUtils {
public static boolean startOrEnd(final StringLocated s) {
final String s2 = StringUtils.trinNoTrace(s.getString());
if (s2.startsWith("@") == false && s2.startsWith("\\") == false) {
if (s2.startsWith("@") == false && s2.startsWith("\\") == false)
return false;
}
return startsWithSymbolAnd("end", s2) || DiagramType.getTypeFromArobaseStart(s2) != DiagramType.UNKNOWN;
}

View File

@ -58,7 +58,7 @@ public class License {
@Override
public String toString() {
// ::comment when __CORE__ or __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__
// ::comment when __CORE__ or __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__ or __GPLV2__
return "GPL";
// ::done
// ::uncomment when __CORE__ or __MIT__
@ -76,6 +76,9 @@ public class License {
// ::uncomment when __LGPL__
// return "LGPL";
// ::done
// ::uncomment when __GPLV2__
// return "GPLv2";
// ::done
}
public static License getCurrent() {
@ -155,7 +158,7 @@ public class License {
}
private void end3(final LicenseInfo licenseInfo, final List<String> text) {
// ::comment when __CORE__ or __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__
// ::comment when __CORE__ or __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__ or __GPLV2__
text.add("PlantUML is free software; you can redistribute it and/or modify it");
text.add("under the terms of the GNU General Public License as published by");
text.add("the Free Software Foundation, either version 3 of the License, or");
@ -188,6 +191,9 @@ public class License {
// ::uncomment when __LGPL__
// addLgpl(licenseInfo, text);
// ::done
// ::uncomment when __GPLV2__
// addGplv2(licenseInfo, text);
// ::done
text.add(" ");
if (licenseInfo.isValid() == false) {
@ -370,22 +376,39 @@ public class License {
// }
// ::done
// ::uncomment when __LGPL__
// private void addLgpl(final LicenseInfo licenseInfo, final List<String> text) {
// text.add("PlantUML is free software; you can redistribute it and/or modify it");
// text.add("under the terms of the GNU Lesser General Public License as published by");
// text.add("the Free Software Foundation, either version 3 of the License, or");
// text.add("(at your option) any later version.");
// text.add(" ");
// text.add("PlantUML distributed in the hope that it will be useful, but");
// text.add("WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY");
// text.add("or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public");
// text.add("License for more details.");
// text.add(" ");
// text.add("You should have received a copy of the GNU Lesser General Public License");
// text.add("along with this library. If not, see <https://www.gnu.org/licenses/>.");
// }
// ::done
// ::uncomment when __LGPL__
// private void addLgpl(final LicenseInfo licenseInfo, final List<String> text) {
// text.add("PlantUML is free software; you can redistribute it and/or modify it");
// text.add("under the terms of the GNU Lesser General Public License as published by");
// text.add("the Free Software Foundation, either version 3 of the License, or");
// text.add("(at your option) any later version.");
// text.add(" ");
// text.add("PlantUML distributed in the hope that it will be useful, but");
// text.add("WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY");
// text.add("or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public");
// text.add("License for more details.");
// text.add(" ");
// text.add("You should have received a copy of the GNU Lesser General Public License");
// text.add("along with this library. If not, see <https://www.gnu.org/licenses/>.");
// }
// ::done
// ::uncomment when __GPLV2__
// private void addGplv2(final LicenseInfo licenseInfo, final List<String> text) {
// text.add("PlantUML is free software; you can redistribute it and/or modify it");
// text.add("under the terms of the GNU General Public License V2 as published by");
// text.add("the Free Software Foundation, either version 2 of the License, or");
// text.add("(at your option) any later version.");
// text.add(" ");
// text.add("PlantUML distributed in the hope that it will be useful, but");
// text.add("WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY");
// text.add("or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public");
// text.add("License for more details.");
// text.add(" ");
// text.add("You should have received a copy of the GNU Lesser General Public License");
// text.add("along with this library. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>.");
// }
// ::done
public static void addLicenseInfo(final List<String> text, LicenseInfo licenseInfo) {
if (licenseInfo.getLicenseType() == LicenseType.NAMED) {

View File

@ -46,7 +46,7 @@ public class Version {
// Warning, "version" should be the same in gradle.properties and Version.java
// Any idea anyone how to magically synchronize those :-) ?
private static final String version = "1.2023.12beta1";
private static final String version = "1.2023.13beta1";
public static String versionString() {
return version;
@ -80,7 +80,7 @@ public class Version {
}
public static long compileTime() {
return 1694629593289L;
return 1697809794384L;
}
public static String compileTimeString() {