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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "silphscope",
3
- "version": "1.4.10",
3
+ "version": "1.4.11",
4
4
  "description": "A firered/leafgreen ROM asset extractor for use in web applications",
5
5
  "main": "main.js",
6
6
  "exports": {
@@ -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, { filterType: 0 });
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, { filterType: 0 });
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, { filterType: 0 });
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, { filterType: 0 });
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, { outputDir });
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, { outputDir });
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 { outputDir = null } = options;
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, { filterType: 0 });
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 { outputDir = null } = options;
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, { filterType: 0 });
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 { outputDir = null } = options;
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, { filterType: 0 });
55
- const buffer2 = PNG.sync.write(pngFrame2, { filterType: 0 });
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, { outputDir });
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, { outputDir });
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, { filterType: 0 });
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, { filterType: 0 });
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, { filterType: 0 });
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, { filterType: 0 });
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 { outputDir = null } = options;
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, { filterType: 0 });
71
- const buffer2 = PNG.sync.write(pngFrame2, { filterType: 0 });
72
- const buffer3 = PNG.sync.write(pngFrame3, { filterType: 0 });
73
- const buffer4 = PNG.sync.write(pngFrame4, { filterType: 0 });
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, { filterType: 0 });
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, { outputDir }); // that could have been bad lol I forgot to add await :p
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, { outputDir });
41
- await renderTrainerBackPic("POKEDUDE", backTrainers, reader, rom, { outputDir });
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, { filterType: 0 });
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}`;