silphscope 1.4.10 → 1.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -0
- package/package.json +1 -1
- package/src/graphics/balls/render-ball-particle.js +10 -2
- package/src/graphics/balls/render-balls.js +12 -2
- package/src/graphics/graphics-extractor-main.js +130 -2
- package/src/graphics/icons/render-icons.js +9 -2
- package/src/graphics/mons/render-mon-foot.js +9 -2
- package/src/graphics/mons/render-mon-icon.js +13 -3
- package/src/graphics/mons/render-mons.js +16 -3
- package/src/graphics/moves/render-moves.js +14 -3
- package/src/graphics/trainers/render-trainer-back-pics.js +25 -6
- package/src/graphics/trainers/render-trainers.js +21 -4
package/README.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
still a WIP however hopefully with some more work I can get this into a workable state...
|
|
2
2
|
|
|
3
|
+
(Small But New Update!) Update:
|
|
4
|
+
|
|
5
|
+
so you can now set stuff such as the pngFilterType and pngCompressionLevel allow me to explain how they work:
|
|
6
|
+
|
|
7
|
+
pngFilterType:
|
|
8
|
+
|
|
9
|
+
This takes a integer between -1 and 4 with each integer corresponding like so:
|
|
10
|
+
|
|
11
|
+
-1: auto
|
|
12
|
+
0: none
|
|
13
|
+
1: sub
|
|
14
|
+
2: up
|
|
15
|
+
3: average
|
|
16
|
+
4: paeth
|
|
17
|
+
|
|
18
|
+
now as to what each of these mean... I don't know exactly lol (I'm not some png genius D:) but from what I understand none of these actually change the look of the image instead they are basically compression some will work better with different images depending on content... that said though it is still somewhat important to point out that paeth is the most computationally expensive but usually results in a smaller file size (most of the time... for an example one image might get marginal file size decreases with a paeth filter meanwhile it would get a larger decrease using average or something) if you do not want to deal with trying to figure out which filter is best it is recommended to set the value to 0 as that will apply no filter onto the image or if you wish for the best filter for each image type to be applied use -1 as this will make it so that each image is tested for which filter is best for it and which is best is applied be aware though this is pretty expensive resource wise (can add on to like 2 seconds to the renderAllGraphics() function... so not crazy but if you need upmost speed perhaps that is an issue for you :p) you can also however pass an array like so:
|
|
19
|
+
|
|
20
|
+
[1, 3, 4]
|
|
21
|
+
|
|
22
|
+
this will make it so that the only png filters allowed to be used are 1, 3, and 4 (sub, average, and paeth) so each image will be tested for each of these filters and the best is chosen out of however many filters you put in the array (not sure why you would want to do this but it's there I guess...)
|
|
23
|
+
|
|
24
|
+
pngCompressionLevel:
|
|
25
|
+
|
|
26
|
+
This one is much simpler it essentially takes a integer between 0-9 with 0 being no compression added at all and 9 being the maximum compression added of course though this also uses more resources so it could cause the render time to be slower (like by 1-2 seconds... once again not crazy but sometimes you need speed I guess... wait I should mention that is measured via the renderAllGraphics() function not 1-2 seconds per asset lol) but it will result in a smaller file meanwhile 0 will be the fastest you can do (since you aren't computing anything...) but it will result in a much larger file
|
|
27
|
+
|
|
3
28
|
(Amazingly Newer!) Update:
|
|
4
29
|
|
|
5
30
|
so now ball extraction works! still need to cut the images up but that should be simple
|
|
@@ -29,6 +54,8 @@ import { renderAllGraphics } from "silphscope"; // this is cool...
|
|
|
29
54
|
const rom = fs.readFileSync("pokefirered.gba"); // replace with path to your own firered rom
|
|
30
55
|
await renderAllGraphics(rom, {
|
|
31
56
|
concurrency: 4, // handles how many concurrent promises are run. Set to 1 to run sequentially and conversly increase to run more promises at once (don't set too high though if your CPU / I/O can't handle it then it might actually be slower...)
|
|
57
|
+
pngFilterType: 0, // view the explanation for this above
|
|
58
|
+
pngCompression: 4, // same thing :p explanation above
|
|
32
59
|
outputMonDir: "./Assets/monImages", // must I explain?
|
|
33
60
|
outputIconDir: "./Assets/Icons", // same thing here :p
|
|
34
61
|
outputTrainerDir: "./Assets/Trainers", // ...
|
|
@@ -50,6 +77,8 @@ import { renderAllMons } from "silphscope"; // never gets old :p
|
|
|
50
77
|
const rom = fs.readFileSync("pokefirered.gba")// once again replace with the path to your own firered rom
|
|
51
78
|
await renderAllMons(rom, {
|
|
52
79
|
concurrency: 4, // handles how many concurrent promises are run. Set to 1 to run sequentially and conversly increase to run more promises at once (don't set too high though if your CPU / I/O can't handle it then it might actually be slower...)
|
|
80
|
+
pngFilterType: 0, // explanation above
|
|
81
|
+
pngCompression: 4, // explanation above
|
|
53
82
|
outputDir: "./Assets/monImages", // do I actually have to explain?
|
|
54
83
|
icon: true, // set to false if you don't want icons I guess...
|
|
55
84
|
footprint: true, // same as the above...
|
|
@@ -64,6 +93,8 @@ import { renderAllIcons } from "silphscope" // :D
|
|
|
64
93
|
const rom = fs.readFileSync("pokefirered.gba")// find your own rom and so on :l
|
|
65
94
|
await renderAllIcons(rom, {
|
|
66
95
|
concurrency: 4, // handles how many concurrent promises are run. Set to 1 to run sequentially and conversly increase to run more promises at once (don't set too high though if your CPU / I/O can't handle it then it might actually be slower...)
|
|
96
|
+
pngFilterType: 0, // explanation above
|
|
97
|
+
pngCompression: 4, // explanation above
|
|
67
98
|
outputDir: "./Assets/Icons" // no comment (wait... that was a comment :p)
|
|
68
99
|
});
|
|
69
100
|
```
|
|
@@ -76,6 +107,8 @@ import { renderAllTrainers } from "silphscope" // :O
|
|
|
76
107
|
const rom = fs.readFileSync("pokefirered.gba") // stuff stuff stuff
|
|
77
108
|
await renderAllTrainers(rom, {
|
|
78
109
|
concurrency: 4, // handles how many concurrent promises are run. Set to 1 to run sequentially and conversly increase to run more promises at once (don't set too high though if your CPU / I/O can't handle it then it might actually be slower...)
|
|
110
|
+
pngFilterType: 0, // explanation above
|
|
111
|
+
pngCompression: 4, // explanation above
|
|
79
112
|
outputDir: "./Assets/trainers", // more stuff
|
|
80
113
|
trainerBackPics: true, // renders the like 8 trainer back pics
|
|
81
114
|
})
|
|
@@ -89,6 +122,8 @@ import { renderAllMoves } from "silphscope" // :O
|
|
|
89
122
|
const rom = fs.readFileSync("pokefirered.gba") // stuff stuff stuff (more stuff!)
|
|
90
123
|
await renderAllMoves(rom, {
|
|
91
124
|
concurrency: 4, // handles how many concurrent promises are run. Set to 1 to run sequentially and conversly increase to run more promises at once (don't set too high though if your CPU / I/O can't handle it then it might actually be slower...)
|
|
125
|
+
pngFilterType: 0, // explanation above
|
|
126
|
+
pngCompression: 4, // explanation above
|
|
92
127
|
outputDir: "./Assets/trainers", // (incredibly) more stuff
|
|
93
128
|
renderMasterImage: true, // kinda forgot about this... basically it renders a uncut image of the move anim if you like
|
|
94
129
|
sortUnused: true, // sorts unused moves into a sub-directory
|
|
@@ -103,6 +138,8 @@ import { renderAllBalls } from "silphscope" // o-O
|
|
|
103
138
|
const rom = fs.readFileSync("./path/to/your/rom.gba") // the file path explains :/
|
|
104
139
|
await renderAllBalls(rom, {
|
|
105
140
|
concurrency: 4, // handles how many concurrent promises are run. Set to 1 to run sequentially and conversly increase to run more promises at once (don't set too high though if your CPU / I/O can't handle it then it might actually be slower...)
|
|
141
|
+
pngFilterType: 0, // explanation above
|
|
142
|
+
pngCompression: 4, // explanation above
|
|
106
143
|
outputDir: "./Assets/Balls",
|
|
107
144
|
ballParticles: true, // set to false if you don't want the ball particles :p
|
|
108
145
|
renderMasterBallImage: true, // set to false if you don't want the uncut image
|
package/package.json
CHANGED
|
@@ -35,6 +35,8 @@ const extractFrameFromImage = (imageData, fullWidth, frameData) => {
|
|
|
35
35
|
|
|
36
36
|
export async function renderBallParticle(ballName, balls, reader, rom, options = {}) {
|
|
37
37
|
const {
|
|
38
|
+
pngFilterType = null,
|
|
39
|
+
pngCompressionLevel = null,
|
|
38
40
|
outputDir = null,
|
|
39
41
|
renderMasterBallParticleImage = false,
|
|
40
42
|
} = options;
|
|
@@ -67,7 +69,10 @@ export async function renderBallParticle(ballName, balls, reader, rom, options =
|
|
|
67
69
|
|
|
68
70
|
const png = new PNG({ width, height });
|
|
69
71
|
png.data = image;
|
|
70
|
-
const pngBuffer = PNG.sync.write(png, {
|
|
72
|
+
const pngBuffer = PNG.sync.write(png, {
|
|
73
|
+
filterType: pngFilterType,
|
|
74
|
+
deflateLevel: pngCompressionLevel,
|
|
75
|
+
});
|
|
71
76
|
|
|
72
77
|
if (outputDir) {
|
|
73
78
|
const dir = `${outputDir}/${ballName}`;
|
|
@@ -81,7 +86,10 @@ export async function renderBallParticle(ballName, balls, reader, rom, options =
|
|
|
81
86
|
|
|
82
87
|
const png = new PNG({ width: frame.width, height: frame.height });
|
|
83
88
|
png.data = frameImageData;
|
|
84
|
-
const pngFrameBuffer = PNG.sync.write(png, {
|
|
89
|
+
const pngFrameBuffer = PNG.sync.write(png, {
|
|
90
|
+
filterType: pngFilterType,
|
|
91
|
+
deflateLevel: pngCompressionLevel,
|
|
92
|
+
});
|
|
85
93
|
|
|
86
94
|
const fileName = `${dir}/particle-${i}.png`;
|
|
87
95
|
fs.writeFileSync(fileName, pngFrameBuffer);
|
|
@@ -36,6 +36,8 @@ const extractFrameFromImage = (imageData, fullWidth, frameData) => {
|
|
|
36
36
|
|
|
37
37
|
export async function renderBall(ballName, balls, reader, rom, options = {}) {
|
|
38
38
|
const {
|
|
39
|
+
pngFilterType = null,
|
|
40
|
+
pngCompressionLevel = null,
|
|
39
41
|
outputDir = null,
|
|
40
42
|
ballParticles = false,
|
|
41
43
|
renderMasterBallImage = false,
|
|
@@ -51,6 +53,8 @@ export async function renderBall(ballName, balls, reader, rom, options = {}) {
|
|
|
51
53
|
}
|
|
52
54
|
if (ballParticles) {
|
|
53
55
|
renderBallParticle(ballName, balls, reader, rom, {
|
|
56
|
+
pngFilterType,
|
|
57
|
+
pngCompressionLevel,
|
|
54
58
|
outputDir,
|
|
55
59
|
renderMasterBallParticleImage,
|
|
56
60
|
});
|
|
@@ -75,7 +79,10 @@ export async function renderBall(ballName, balls, reader, rom, options = {}) {
|
|
|
75
79
|
|
|
76
80
|
const png = new PNG({ width, height });
|
|
77
81
|
png.data = image;
|
|
78
|
-
const pngBuffer = PNG.sync.write(png, {
|
|
82
|
+
const pngBuffer = PNG.sync.write(png, {
|
|
83
|
+
filterType: pngFilterType,
|
|
84
|
+
deflateLevel: pngCompressionLevel,
|
|
85
|
+
});
|
|
79
86
|
|
|
80
87
|
if (outputDir) {
|
|
81
88
|
const dir = `${outputDir}/${ballName}`;
|
|
@@ -89,7 +96,10 @@ export async function renderBall(ballName, balls, reader, rom, options = {}) {
|
|
|
89
96
|
|
|
90
97
|
const png = new PNG({ width: frame.width, height: frame.height });
|
|
91
98
|
png.data = frameImageData;
|
|
92
|
-
const pngFrameBuffer = PNG.sync.write(png, {
|
|
99
|
+
const pngFrameBuffer = PNG.sync.write(png, {
|
|
100
|
+
filterType: pngFilterType,
|
|
101
|
+
deflateLevel: pngCompressionLevel,
|
|
102
|
+
});
|
|
93
103
|
|
|
94
104
|
const fileName = `${dir}/frame-${i}.png`;
|
|
95
105
|
await fs.promises.writeFile(fileName, pngFrameBuffer);
|
|
@@ -27,6 +27,19 @@ const trainersBack = loadDefaultJson("../trainer-data/trainerBackData.json");
|
|
|
27
27
|
const moves = loadDefaultJson("../move-data/moveData.json");
|
|
28
28
|
const balls = loadDefaultJson("../ball-data/ballData.json");
|
|
29
29
|
|
|
30
|
+
function isValidFilterType(filterTypeValue) {
|
|
31
|
+
if (Number.isInteger(filterTypeValue)) {
|
|
32
|
+
return filterTypeValue >= -1 && filterTypeValue <= 4;
|
|
33
|
+
}
|
|
34
|
+
if (Array.isArray(filterTypeValue)) {
|
|
35
|
+
return filterTypeValue.length > 0 && filterTypeValue.every(entry =>
|
|
36
|
+
Number.isInteger(entry) && entry >= 0 && entry <= 4
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
30
43
|
export async function renderAllMons(rom, options = {}) {
|
|
31
44
|
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
32
45
|
throw new TypeError("renderAllMons(rom, options) requires rom Buffer/Uint8Array as first argument");
|
|
@@ -36,10 +49,22 @@ export async function renderAllMons(rom, options = {}) {
|
|
|
36
49
|
mons: providedMons = mons,
|
|
37
50
|
outputDir = "./out",
|
|
38
51
|
concurrency = 4,
|
|
52
|
+
pngFilterType = 0,
|
|
53
|
+
pngCompressionLevel = 4,
|
|
39
54
|
icon = true,
|
|
40
55
|
footprint = true,
|
|
41
56
|
} = options;
|
|
42
57
|
|
|
58
|
+
if (!Number.isInteger(concurrency) || concurrency < 1) {
|
|
59
|
+
throw new TypeError(`renderAllMons(rom, options = { concurrency, ... }) requires concurrency to be a integer greater than 0 (recieved ${concurrency})`);
|
|
60
|
+
}
|
|
61
|
+
if (isValidFilterType(pngFilterType)) {
|
|
62
|
+
throw new TypeError(`renderAllMons(rom, options = { pngFilterType, ... }) requires pngFilterType to be a integer between -1 and 4 (received ${pngFilterType})`)
|
|
63
|
+
}
|
|
64
|
+
if (!Number.isInteger(pngCompressionLevel) || pngCompressionLevel < 0 || pngCompressionLevel > 9) {
|
|
65
|
+
throw new TypeError(`renderAllMons(rom, options = { pngCompressionLevel, ... }) requires pngCompressionLevel to be a integer between 0 and 9 (received ${pngCompressionLevel})`)
|
|
66
|
+
}
|
|
67
|
+
|
|
43
68
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
44
69
|
|
|
45
70
|
const config = getRomConfig(rom);
|
|
@@ -52,6 +77,8 @@ export async function renderAllMons(rom, options = {}) {
|
|
|
52
77
|
variant: ["normal", "shiny"],
|
|
53
78
|
icon,
|
|
54
79
|
footprint,
|
|
80
|
+
pngFilterType,
|
|
81
|
+
pngCompressionLevel,
|
|
55
82
|
outputDir,
|
|
56
83
|
});
|
|
57
84
|
console.log(`Done: ${monName}`);
|
|
@@ -59,9 +86,12 @@ export async function renderAllMons(rom, options = {}) {
|
|
|
59
86
|
} else {
|
|
60
87
|
for (const monName of Object.keys(providedMons)) {
|
|
61
88
|
await renderMon(monName, providedMons, reader, rom, {
|
|
89
|
+
side: ["front", "back"],
|
|
62
90
|
variant: ["normal", "shiny"],
|
|
63
91
|
icon,
|
|
64
92
|
footprint,
|
|
93
|
+
pngFilterType,
|
|
94
|
+
pngCompressionLevel,
|
|
65
95
|
outputDir,
|
|
66
96
|
});
|
|
67
97
|
console.log(`Done: ${monName}`);
|
|
@@ -77,9 +107,21 @@ export async function renderAllIcons(rom, options = {}) {
|
|
|
77
107
|
const {
|
|
78
108
|
icons: providedIcons = icons,
|
|
79
109
|
concurrency = 4,
|
|
110
|
+
pngFilterType = 0,
|
|
111
|
+
pngCompressionLevel = 4,
|
|
80
112
|
outputDir = "./out",
|
|
81
113
|
} = options;
|
|
82
114
|
|
|
115
|
+
if (!Number.isInteger(concurrency) || concurrency < 1) {
|
|
116
|
+
throw new TypeError(`renderAllIcons(rom, options = { concurrency, ... }) requires concurrency to be a integer greater than 0 (recieved ${concurrency})`);
|
|
117
|
+
}
|
|
118
|
+
if (isValidFilterType(pngFilterType)) {
|
|
119
|
+
throw new TypeError(`renderAllIcons(rom, options = { pngFilterType, ... }) requires pngFilterType to be a integer between -1 and 4 (received ${pngFilterType})`)
|
|
120
|
+
}
|
|
121
|
+
if (!Number.isInteger(pngCompressionLevel) || pngCompressionLevel < 0 || pngCompressionLevel > 9) {
|
|
122
|
+
throw new TypeError(`renderAllIcons(rom, options = { pngCompressionLevel, ... }) requires pngCompressionLevel to be a integer between 0 and 9 (received ${pngCompressionLevel})`)
|
|
123
|
+
}
|
|
124
|
+
|
|
83
125
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
84
126
|
|
|
85
127
|
const config = getRomConfig(rom);
|
|
@@ -87,12 +129,20 @@ export async function renderAllIcons(rom, options = {}) {
|
|
|
87
129
|
|
|
88
130
|
if (concurrency > 1) {
|
|
89
131
|
await mapLimit(Object.keys(providedIcons), concurrency, async (itemName) => {
|
|
90
|
-
await renderIcon(itemName, providedIcons, reader, rom, {
|
|
132
|
+
await renderIcon(itemName, providedIcons, reader, rom, {
|
|
133
|
+
pngFilterType,
|
|
134
|
+
pngCompressionLevel,
|
|
135
|
+
outputDir,
|
|
136
|
+
});
|
|
91
137
|
console.log(`Done: ${itemName}`);
|
|
92
138
|
});
|
|
93
139
|
} else {
|
|
94
140
|
for (const itemName of Object.keys(providedIcons)) {
|
|
95
|
-
await renderIcon(itemName, providedIcons, reader, rom, {
|
|
141
|
+
await renderIcon(itemName, providedIcons, reader, rom, {
|
|
142
|
+
pngFilterType,
|
|
143
|
+
pngCompressionLevel,
|
|
144
|
+
outputDir,
|
|
145
|
+
});
|
|
96
146
|
console.log(`Done: ${itemName}`);
|
|
97
147
|
}
|
|
98
148
|
}
|
|
@@ -108,9 +158,21 @@ export async function renderAllTrainers(rom, options = {}) {
|
|
|
108
158
|
trainersBack: providedBackTrainers = trainersBack,
|
|
109
159
|
trainerBackPics = true,
|
|
110
160
|
concurrency = 4,
|
|
161
|
+
pngFilterType = 0,
|
|
162
|
+
pngCompressionLevel = 4,
|
|
111
163
|
outputDir = "./out",
|
|
112
164
|
} = options;
|
|
113
165
|
|
|
166
|
+
if (!Number.isInteger(concurrency) || concurrency < 1) {
|
|
167
|
+
throw new TypeError(`renderAllTrainers(rom, options = { concurrency, ... }) requires concurrency to be a integer greater than 0 (recieved ${concurrency})`);
|
|
168
|
+
}
|
|
169
|
+
if (isValidFilterType(pngFilterType)) {
|
|
170
|
+
throw new TypeError(`renderAllTrainers(rom, options = { pngFilterType, ... }) requires pngFilterType to be a integer between -1 and 4 (received ${pngFilterType})`)
|
|
171
|
+
}
|
|
172
|
+
if (!Number.isInteger(pngCompressionLevel) || pngCompressionLevel < 0 || pngCompressionLevel > 9) {
|
|
173
|
+
throw new TypeError(`renderAllTrainers(rom, options = { pngCompressionLevel, ... }) requires pngCompressionLevel to be a integer between 0 and 9 (received ${pngCompressionLevel})`)
|
|
174
|
+
}
|
|
175
|
+
|
|
114
176
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
115
177
|
|
|
116
178
|
const config = getRomConfig(rom);
|
|
@@ -120,6 +182,8 @@ export async function renderAllTrainers(rom, options = {}) {
|
|
|
120
182
|
await mapLimit(Object.keys(providedTrainers), concurrency, async (trainerName) => {
|
|
121
183
|
await renderTrainer(trainerName, providedTrainers, providedBackTrainers, reader, rom, {
|
|
122
184
|
trainerBackPics,
|
|
185
|
+
pngFilterType,
|
|
186
|
+
pngCompressionLevel,
|
|
123
187
|
outputDir
|
|
124
188
|
});
|
|
125
189
|
console.log(`Done: ${trainerName}`);
|
|
@@ -128,6 +192,8 @@ export async function renderAllTrainers(rom, options = {}) {
|
|
|
128
192
|
for (const trainerName of Object.keys(providedTrainers)) {
|
|
129
193
|
await renderTrainer(trainerName, providedTrainers, providedBackTrainers, reader, rom, {
|
|
130
194
|
trainerBackPics,
|
|
195
|
+
pngFilterType,
|
|
196
|
+
pngCompressionLevel,
|
|
131
197
|
outputDir
|
|
132
198
|
});
|
|
133
199
|
console.log(`Done: ${trainerName}`);
|
|
@@ -136,14 +202,30 @@ export async function renderAllTrainers(rom, options = {}) {
|
|
|
136
202
|
}
|
|
137
203
|
|
|
138
204
|
export async function renderAllMoves(rom, options = {}) {
|
|
205
|
+
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
206
|
+
throw new TypeError("renderAllMoves(rom, options) requires rom Buffer/Uint8Array as first argument");
|
|
207
|
+
}
|
|
208
|
+
|
|
139
209
|
const {
|
|
140
210
|
moves: providedMoves = moves,
|
|
141
211
|
concurrency = 4,
|
|
212
|
+
pngFilterType = 0,
|
|
213
|
+
pngCompressionLevel = 4,
|
|
142
214
|
outputDir = "./out",
|
|
143
215
|
renderMasterImage = true,
|
|
144
216
|
sortUnused = true,
|
|
145
217
|
} = options;
|
|
146
218
|
|
|
219
|
+
if (!Number.isInteger(concurrency) || concurrency < 1) {
|
|
220
|
+
throw new TypeError(`renderAllMoves(rom, options = { concurrency, ... }) requires concurrency to be a integer greater than 0 (recieved ${concurrency})`);
|
|
221
|
+
}
|
|
222
|
+
if (isValidFilterType(pngFilterType)) {
|
|
223
|
+
throw new TypeError(`renderAllMoves(rom, options = { pngFilterType, ... }) requires pngFilterType to be a integer between -1 and 4 (received ${pngFilterType})`)
|
|
224
|
+
}
|
|
225
|
+
if (!Number.isInteger(pngCompressionLevel) || pngCompressionLevel < 0 || pngCompressionLevel > 9) {
|
|
226
|
+
throw new TypeError(`renderAllMoves(rom, options = { pngCompressionLevel, ... }) requires pngCompressionLevel to be a integer between 0 and 9 (received ${pngCompressionLevel})`)
|
|
227
|
+
}
|
|
228
|
+
|
|
147
229
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
148
230
|
|
|
149
231
|
const config = getRomConfig(rom);
|
|
@@ -152,6 +234,8 @@ export async function renderAllMoves(rom, options = {}) {
|
|
|
152
234
|
if (concurrency > 1) {
|
|
153
235
|
await mapLimit(Object.keys(providedMoves), concurrency, async (moveName) => {
|
|
154
236
|
await renderMove(moveName, providedMoves, reader, rom, {
|
|
237
|
+
pngFilterType,
|
|
238
|
+
pngCompressionLevel,
|
|
155
239
|
outputDir,
|
|
156
240
|
renderMasterImage,
|
|
157
241
|
sortUnused,
|
|
@@ -161,6 +245,8 @@ export async function renderAllMoves(rom, options = {}) {
|
|
|
161
245
|
} else {
|
|
162
246
|
for (const moveName of Object.keys(providedMoves)) {
|
|
163
247
|
await renderMove(moveName, providedMoves, reader, rom, {
|
|
248
|
+
pngFilterType,
|
|
249
|
+
pngCompressionLevel,
|
|
164
250
|
outputDir,
|
|
165
251
|
renderMasterImage,
|
|
166
252
|
sortUnused,
|
|
@@ -171,15 +257,31 @@ export async function renderAllMoves(rom, options = {}) {
|
|
|
171
257
|
}
|
|
172
258
|
|
|
173
259
|
export async function renderAllBalls(rom, options = {}) {
|
|
260
|
+
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
261
|
+
throw new TypeError("renderAllBalls(rom, options) requires rom Buffer/Uint8Array as first argument");
|
|
262
|
+
}
|
|
263
|
+
|
|
174
264
|
const {
|
|
175
265
|
balls: providedBalls = balls,
|
|
176
266
|
concurrency = 4,
|
|
267
|
+
pngFilterType = 0,
|
|
268
|
+
pngCompressionLevel = 4,
|
|
177
269
|
outputDir = "./out",
|
|
178
270
|
ballParticles = true,
|
|
179
271
|
renderMasterBallImage = true,
|
|
180
272
|
renderMasterBallParticleImage = true,
|
|
181
273
|
} = options;
|
|
182
274
|
|
|
275
|
+
if (!Number.isInteger(concurrency) || concurrency < 1) {
|
|
276
|
+
throw new TypeError(`renderAllBalls(rom, options = { concurrency, ... }) requires concurrency to be a integer greater than 0 (recieved ${concurrency})`);
|
|
277
|
+
}
|
|
278
|
+
if (isValidFilterType(pngFilterType)) {
|
|
279
|
+
throw new TypeError(`renderAllBalls(rom, options = { pngFilterType, ... }) requires pngFilterType to be a integer between -1 and 4 (received ${pngFilterType})`)
|
|
280
|
+
}
|
|
281
|
+
if (!Number.isInteger(pngCompressionLevel) || pngCompressionLevel < 0 || pngCompressionLevel > 9) {
|
|
282
|
+
throw new TypeError(`renderAllBalls(rom, options = { pngCompressionLevel, ... }) requires pngCompressionLevel to be a integer between 0 and 9 (received ${pngCompressionLevel})`)
|
|
283
|
+
}
|
|
284
|
+
|
|
183
285
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
184
286
|
|
|
185
287
|
const config = getRomConfig(rom);
|
|
@@ -188,6 +290,8 @@ export async function renderAllBalls(rom, options = {}) {
|
|
|
188
290
|
if (concurrency > 1) {
|
|
189
291
|
await mapLimit(Object.keys(providedBalls), concurrency, async (ballName) => {
|
|
190
292
|
await renderBall(ballName, providedBalls, reader, rom, {
|
|
293
|
+
pngFilterType,
|
|
294
|
+
pngCompressionLevel,
|
|
191
295
|
outputDir,
|
|
192
296
|
ballParticles,
|
|
193
297
|
renderMasterBallImage,
|
|
@@ -198,6 +302,8 @@ export async function renderAllBalls(rom, options = {}) {
|
|
|
198
302
|
} else {
|
|
199
303
|
for (const ballName of Object.keys(providedBalls)) {
|
|
200
304
|
await renderBall(ballName, providedBalls, reader, rom, {
|
|
305
|
+
pngFilterType,
|
|
306
|
+
pngCompressionLevel,
|
|
201
307
|
outputDir,
|
|
202
308
|
ballParticles,
|
|
203
309
|
renderMasterBallImage,
|
|
@@ -215,6 +321,8 @@ export async function renderAllGraphics(rom, options = {}) { // eventually I wil
|
|
|
215
321
|
|
|
216
322
|
const {
|
|
217
323
|
concurrency = 4,
|
|
324
|
+
pngFilterType = 0,
|
|
325
|
+
pngCompressionLevel = 4,
|
|
218
326
|
outputMonDir = "./out/mons",
|
|
219
327
|
outputIconDir = "./out/icons",
|
|
220
328
|
outputTrainerDir = "./out/trainers",
|
|
@@ -223,8 +331,20 @@ export async function renderAllGraphics(rom, options = {}) { // eventually I wil
|
|
|
223
331
|
outputBallDir = "./out/balls",
|
|
224
332
|
} = options;
|
|
225
333
|
|
|
334
|
+
if (!Number.isInteger(concurrency) || concurrency < 1) {
|
|
335
|
+
throw new TypeError(`renderAllGraphics(rom, options = { concurrency, ... }) requires concurrency to be a integer greater than 0 (recieved ${concurrency})`);
|
|
336
|
+
}
|
|
337
|
+
if (isValidFilterType(pngFilterType)) {
|
|
338
|
+
throw new Error(`renderAllGraphics(rom, options = { pngFilterType, ... }) requires pngFilterType to be a integer between -1 and 4 (received ${pngFilterType})`)
|
|
339
|
+
}
|
|
340
|
+
if (!Number.isInteger(pngCompressionLevel) || pngCompressionLevel < 0 || pngCompressionLevel > 9) {
|
|
341
|
+
throw new Error(`renderAllGraphics(rom, options = { pngCompressionLevel, ... }) requires pngCompressionLevel to be a integer between 0 and 9 (received ${pngCompressionLevel})`)
|
|
342
|
+
}
|
|
343
|
+
|
|
226
344
|
await renderAllMons(rom, {
|
|
227
345
|
concurrency,
|
|
346
|
+
pngFilterType,
|
|
347
|
+
pngCompressionLevel,
|
|
228
348
|
outputDir: outputMonDir,
|
|
229
349
|
icon: true,
|
|
230
350
|
footprint: true,
|
|
@@ -232,17 +352,23 @@ export async function renderAllGraphics(rom, options = {}) { // eventually I wil
|
|
|
232
352
|
|
|
233
353
|
await renderAllIcons(rom, {
|
|
234
354
|
concurrency,
|
|
355
|
+
pngFilterType,
|
|
356
|
+
pngCompressionLevel,
|
|
235
357
|
outputDir: outputIconDir,
|
|
236
358
|
});
|
|
237
359
|
|
|
238
360
|
await renderAllTrainers(rom, {
|
|
239
361
|
concurrency,
|
|
362
|
+
pngFilterType,
|
|
363
|
+
pngCompressionLevel,
|
|
240
364
|
outputDir: outputTrainerDir,
|
|
241
365
|
trainerBackPics: true,
|
|
242
366
|
});
|
|
243
367
|
|
|
244
368
|
await renderAllMoves(rom, {
|
|
245
369
|
concurrency,
|
|
370
|
+
pngFilterType,
|
|
371
|
+
pngCompressionLevel,
|
|
246
372
|
outputDir: outputMoveDir,
|
|
247
373
|
renderMasterImage: true,
|
|
248
374
|
sortUnused: sortUnusedMoves,
|
|
@@ -250,6 +376,8 @@ export async function renderAllGraphics(rom, options = {}) { // eventually I wil
|
|
|
250
376
|
|
|
251
377
|
await renderAllBalls(rom, {
|
|
252
378
|
concurrency,
|
|
379
|
+
pngFilterType,
|
|
380
|
+
pngCompressionLevel,
|
|
253
381
|
outputDir: outputBallDir,
|
|
254
382
|
ballParticles: true,
|
|
255
383
|
renderMasterBallImage: true,
|
|
@@ -15,7 +15,11 @@ const streamToBuffer = (stream) => new Promise((resolve, reject) => {
|
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
export async function renderIcon(itemName, items, reader, rom, options = {}) {
|
|
18
|
-
const {
|
|
18
|
+
const {
|
|
19
|
+
pngFilterType = null,
|
|
20
|
+
pngCompressionType = null,
|
|
21
|
+
outputDir = null
|
|
22
|
+
} = options;
|
|
19
23
|
|
|
20
24
|
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
21
25
|
throw new TypeError("renderIcon(..., rom) requires a ROM Buffer/Uint8Array");
|
|
@@ -46,7 +50,10 @@ export async function renderIcon(itemName, items, reader, rom, options = {}) {
|
|
|
46
50
|
|
|
47
51
|
const png = new PNG({ width, height });
|
|
48
52
|
png.data = image;
|
|
49
|
-
const pngBuffer = PNG.sync.write(png, {
|
|
53
|
+
const pngBuffer = PNG.sync.write(png, {
|
|
54
|
+
filterType: pngFilterType,
|
|
55
|
+
deflateLevel: pngCompressionType,
|
|
56
|
+
});
|
|
50
57
|
|
|
51
58
|
if (outputDir) {
|
|
52
59
|
const dir = `${outputDir}/${itemName}`;
|
|
@@ -15,7 +15,11 @@ const streamToBuffer = (stream) => new Promise((resolve, reject) => {
|
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
export async function renderMonFoot(monName, mons, reader, rom, options = {}) {
|
|
18
|
-
const {
|
|
18
|
+
const {
|
|
19
|
+
pngFilterType = null,
|
|
20
|
+
pngCompressionType = null,
|
|
21
|
+
outputDir = null,
|
|
22
|
+
} = options;
|
|
19
23
|
|
|
20
24
|
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
21
25
|
throw new TypeError("renderMonFoot(..., rom) requires a ROM Buffer/Uint8Array");
|
|
@@ -70,7 +74,10 @@ export async function renderMonFoot(monName, mons, reader, rom, options = {}) {
|
|
|
70
74
|
|
|
71
75
|
const png = new PNG({ width, height });
|
|
72
76
|
png.data = image;
|
|
73
|
-
const pngBuffer = PNG.sync.write(png, {
|
|
77
|
+
const pngBuffer = PNG.sync.write(png, {
|
|
78
|
+
filterType: pngFilterType,
|
|
79
|
+
deflateLevel: pngCompressionType,
|
|
80
|
+
});
|
|
74
81
|
|
|
75
82
|
if (outputDir) {
|
|
76
83
|
const dir = `${outputDir}/${monName}`;
|
|
@@ -16,7 +16,11 @@ const streamToBuffer = (stream) => new Promise((resolve, reject) => {
|
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
export async function renderMonIcon(monName, mons, reader, rom, options = {}) {
|
|
19
|
-
const {
|
|
19
|
+
const {
|
|
20
|
+
pngFilterType = null,
|
|
21
|
+
pngCompressionLevel = null,
|
|
22
|
+
outputDir = null
|
|
23
|
+
} = options;
|
|
20
24
|
|
|
21
25
|
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
22
26
|
throw new TypeError("renderMonIcon(..., rom) requires a ROM Buffer/Uint8Array");
|
|
@@ -51,8 +55,14 @@ export async function renderMonIcon(monName, mons, reader, rom, options = {}) {
|
|
|
51
55
|
pngFrame1.data = frame1;
|
|
52
56
|
const pngFrame2 = new PNG({ width, height: frameHeight });
|
|
53
57
|
pngFrame2.data = frame2;
|
|
54
|
-
const buffer1 = PNG.sync.write(pngFrame1, {
|
|
55
|
-
|
|
58
|
+
const buffer1 = PNG.sync.write(pngFrame1, {
|
|
59
|
+
filterType: pngFilterType,
|
|
60
|
+
deflateLevel: pngCompressionLevel,
|
|
61
|
+
});
|
|
62
|
+
const buffer2 = PNG.sync.write(pngFrame2, {
|
|
63
|
+
filterType: pngFilterType,
|
|
64
|
+
deflateLevel: pngCompressionLevel,
|
|
65
|
+
});
|
|
56
66
|
|
|
57
67
|
if (outputDir) {
|
|
58
68
|
const dir = `${outputDir}/${monName}`;
|
|
@@ -23,6 +23,8 @@ export async function renderMon(monName, mons, reader, rom, options = {}) {
|
|
|
23
23
|
variant = "normal",
|
|
24
24
|
icon = false,
|
|
25
25
|
footprint = false,
|
|
26
|
+
pngFilterType = null,
|
|
27
|
+
pngCompressionLevel = null,
|
|
26
28
|
outputDir = null,
|
|
27
29
|
} = options;
|
|
28
30
|
|
|
@@ -34,10 +36,18 @@ export async function renderMon(monName, mons, reader, rom, options = {}) {
|
|
|
34
36
|
const variants = Array.isArray(variant) ? variant : [variant];
|
|
35
37
|
|
|
36
38
|
if (icon === true) {
|
|
37
|
-
await renderMonIcon(monName, mons, reader, rom, {
|
|
39
|
+
await renderMonIcon(monName, mons, reader, rom, {
|
|
40
|
+
pngFilterType,
|
|
41
|
+
pngCompressionLevel,
|
|
42
|
+
outputDir,
|
|
43
|
+
});
|
|
38
44
|
}
|
|
39
45
|
if (footprint === true) {
|
|
40
|
-
await renderMonFoot(monName, mons, reader, rom, {
|
|
46
|
+
await renderMonFoot(monName, mons, reader, rom, {
|
|
47
|
+
pngFilterType,
|
|
48
|
+
pngCompressionLevel,
|
|
49
|
+
outputDir,
|
|
50
|
+
});
|
|
41
51
|
}
|
|
42
52
|
|
|
43
53
|
const mon = mons[monName];
|
|
@@ -76,7 +86,10 @@ export async function renderMon(monName, mons, reader, rom, options = {}) {
|
|
|
76
86
|
|
|
77
87
|
const png = new PNG({ width, height });
|
|
78
88
|
png.data = image;
|
|
79
|
-
const pngBuffer = PNG.sync.write(png, {
|
|
89
|
+
const pngBuffer = PNG.sync.write(png, {
|
|
90
|
+
filterType: pngFilterType,
|
|
91
|
+
deflateLevel: pngCompressionLevel,
|
|
92
|
+
});
|
|
80
93
|
|
|
81
94
|
if (outputDir) {
|
|
82
95
|
const dir = `${outputDir}/${monName}`;
|
|
@@ -37,6 +37,8 @@ const extractFrameFromImage = (imageData, fullWidth, frameData) => { // in theor
|
|
|
37
37
|
|
|
38
38
|
export async function renderMove(moveName, moves, reader, rom, options = {}) {
|
|
39
39
|
const {
|
|
40
|
+
pngFilterType = null,
|
|
41
|
+
pngCompressionLevel = null,
|
|
40
42
|
outputDir = null,
|
|
41
43
|
renderMasterImage = false,
|
|
42
44
|
sortUnused = false,
|
|
@@ -70,7 +72,10 @@ export async function renderMove(moveName, moves, reader, rom, options = {}) {
|
|
|
70
72
|
|
|
71
73
|
const png = new PNG({ width, height });
|
|
72
74
|
png.data = image;
|
|
73
|
-
const pngBuffer = PNG.sync.write(png, {
|
|
75
|
+
const pngBuffer = PNG.sync.write(png, {
|
|
76
|
+
filterType: pngFilterType,
|
|
77
|
+
deflateLevel: pngCompressionLevel,
|
|
78
|
+
});
|
|
74
79
|
|
|
75
80
|
if (outputDir) { // I will update this later but in theory it should also work... eventually though it will need a split inside to handle full image generation :p
|
|
76
81
|
const rootDir = (sortUnused && move?.unused === true)? `${outputDir}/unused` : `${outputDir}`
|
|
@@ -79,7 +84,10 @@ export async function renderMove(moveName, moves, reader, rom, options = {}) {
|
|
|
79
84
|
if (renderMasterImage) {
|
|
80
85
|
const png = new PNG({ width, height });
|
|
81
86
|
png.data = image;
|
|
82
|
-
const pngBuffer = PNG.sync.write(png, {
|
|
87
|
+
const pngBuffer = PNG.sync.write(png, {
|
|
88
|
+
filterType: pngFilterType,
|
|
89
|
+
deflateLevel: pngCompressionLevel,
|
|
90
|
+
});
|
|
83
91
|
await fs.promises.writeFile(`${dir}/master.png`, pngBuffer);
|
|
84
92
|
}
|
|
85
93
|
for (let i = 0; i < move.frames.length; i++) {
|
|
@@ -88,7 +96,10 @@ export async function renderMove(moveName, moves, reader, rom, options = {}) {
|
|
|
88
96
|
|
|
89
97
|
const png = new PNG({ width: frame.width, height: frame.height });
|
|
90
98
|
png.data = frameImageData;
|
|
91
|
-
const pngBuffer = PNG.sync.write(png, {
|
|
99
|
+
const pngBuffer = PNG.sync.write(png, {
|
|
100
|
+
filterType: pngFilterType,
|
|
101
|
+
deflateLevel: pngCompressionLevel,
|
|
102
|
+
});
|
|
92
103
|
|
|
93
104
|
const fileName = `${dir}/frame-${i}.png`;
|
|
94
105
|
await fs.promises.writeFile(fileName, pngBuffer);
|
|
@@ -16,7 +16,11 @@ const streamToBuffer = (stream) => new Promise((resolve, reject) => {
|
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
export async function renderTrainerBackPic(trainerName, trainers, reader, rom, options = {}) {
|
|
19
|
-
const {
|
|
19
|
+
const {
|
|
20
|
+
pngFilterType = null,
|
|
21
|
+
pngCompressionLevel = null,
|
|
22
|
+
outputDir = null
|
|
23
|
+
} = options;
|
|
20
24
|
|
|
21
25
|
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
22
26
|
throw new TypeError("renderTrainerBackPic(..., rom) requires a ROM Buffer/Uint8Array");
|
|
@@ -67,10 +71,22 @@ export async function renderTrainerBackPic(trainerName, trainers, reader, rom, o
|
|
|
67
71
|
pngFrame3.data = frame3;
|
|
68
72
|
const pngFrame4 = new PNG({ width, height: frameHeight });
|
|
69
73
|
pngFrame4.data = frame4;
|
|
70
|
-
const buffer1 = PNG.sync.write(pngFrame1, {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
const buffer1 = PNG.sync.write(pngFrame1, {
|
|
75
|
+
filterType: pngFilterType,
|
|
76
|
+
deflateLevel: pngCompressionLevel,
|
|
77
|
+
});
|
|
78
|
+
const buffer2 = PNG.sync.write(pngFrame2, {
|
|
79
|
+
filterType: pngFilterType,
|
|
80
|
+
deflateLevel: pngCompressionLevel,
|
|
81
|
+
});
|
|
82
|
+
const buffer3 = PNG.sync.write(pngFrame3, {
|
|
83
|
+
filterType: pngFilterType,
|
|
84
|
+
deflateLevel: pngCompressionLevel,
|
|
85
|
+
});
|
|
86
|
+
const buffer4 = PNG.sync.write(pngFrame4, {
|
|
87
|
+
filterType: pngFilterType,
|
|
88
|
+
deflateLevel: pngCompressionLevel,
|
|
89
|
+
});
|
|
74
90
|
let buffer5
|
|
75
91
|
|
|
76
92
|
if (outputDir) {
|
|
@@ -83,7 +99,10 @@ export async function renderTrainerBackPic(trainerName, trainers, reader, rom, o
|
|
|
83
99
|
if (frame5) {
|
|
84
100
|
const pngFrame5 = new PNG({ width, height: frameHeight });
|
|
85
101
|
pngFrame5.data = frame5;
|
|
86
|
-
buffer5 = PNG.sync.write(pngFrame5, {
|
|
102
|
+
buffer5 = PNG.sync.write(pngFrame5, {
|
|
103
|
+
filterType: pngFilterType,
|
|
104
|
+
deflateLevel: pngCompressionLevel,
|
|
105
|
+
});
|
|
87
106
|
fs.writeFileSync(`${dir}/trainer_back_frame_5.png`, buffer5);
|
|
88
107
|
}
|
|
89
108
|
}
|
|
@@ -19,6 +19,8 @@ const streamToBuffer = (stream) => new Promise((resolve, reject) => {
|
|
|
19
19
|
export async function renderTrainer(trainerName, trainers, backTrainers, reader, rom, options = {}) {
|
|
20
20
|
const {
|
|
21
21
|
trainerBackPics = false,
|
|
22
|
+
pngFilterType = null,
|
|
23
|
+
pngCompressionLevel = null,
|
|
22
24
|
outputDir = null,
|
|
23
25
|
} = options;
|
|
24
26
|
if (!rom || !(rom instanceof Uint8Array || Buffer.isBuffer(rom))) {
|
|
@@ -34,11 +36,23 @@ export async function renderTrainer(trainerName, trainers, backTrainers, reader,
|
|
|
34
36
|
? trainerName
|
|
35
37
|
: false;
|
|
36
38
|
if (backTrainerName) {
|
|
37
|
-
await renderTrainerBackPic(backTrainerName, backTrainers, reader, rom, {
|
|
39
|
+
await renderTrainerBackPic(backTrainerName, backTrainers, reader, rom, {
|
|
40
|
+
pngFilterType,
|
|
41
|
+
pngCompressionLevel,
|
|
42
|
+
outputDir,
|
|
43
|
+
}); // that could have been bad lol I forgot to add await :p
|
|
38
44
|
}
|
|
39
45
|
else if (backTrainerName === false && trainerName === "PAINTER") {
|
|
40
|
-
await renderTrainerBackPic("OLDMAN", backTrainers, reader, rom, {
|
|
41
|
-
|
|
46
|
+
await renderTrainerBackPic("OLDMAN", backTrainers, reader, rom, {
|
|
47
|
+
pngFilterType,
|
|
48
|
+
pngCompressionLevel,
|
|
49
|
+
outputDir,
|
|
50
|
+
});
|
|
51
|
+
await renderTrainerBackPic("POKEDUDE", backTrainers, reader, rom, {
|
|
52
|
+
pngFilterType,
|
|
53
|
+
pngCompressionLevel,
|
|
54
|
+
outputDir,
|
|
55
|
+
});
|
|
42
56
|
}
|
|
43
57
|
}
|
|
44
58
|
const trainerPal = resolveTrainerFrontPicPal(trainer, reader, trainerName);
|
|
@@ -62,7 +76,10 @@ export async function renderTrainer(trainerName, trainers, backTrainers, reader,
|
|
|
62
76
|
|
|
63
77
|
const png = new PNG({ width, height });
|
|
64
78
|
png.data = image;
|
|
65
|
-
const pngBuffer = PNG.sync.write(png, {
|
|
79
|
+
const pngBuffer = PNG.sync.write(png, {
|
|
80
|
+
filterType: pngFilterType,
|
|
81
|
+
deflateLevel: pngCompressionLevel,
|
|
82
|
+
});
|
|
66
83
|
|
|
67
84
|
if (outputDir) {
|
|
68
85
|
const dir = `${outputDir}/${trainerName}`;
|