miijs 1.0.0

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/index.js ADDED
@@ -0,0 +1,966 @@
1
+ const fs = require('fs');
2
+ const { createCanvas, loadImage } = require('canvas');
3
+ const jsQR = require('jsqr');
4
+ var Jimp = require('jimp');
5
+ const QRCode = require('qrcode');
6
+ const httpsLib = require('https');
7
+ const asmCrypto=require("./asmCrypto.js");
8
+ function getKeyByValue(object, value) {
9
+ for (var key in object) {
10
+ if (object[key] === value) {
11
+ return key;
12
+ }
13
+ }
14
+ }
15
+
16
+ var binary;
17
+ function getBinaryFromAddress(addr){//EG: 0x20
18
+ let byte = binary.readUInt8(addr);
19
+ let binaryString = '';
20
+ for (let i = 7; i >= 0; i--) {
21
+ binaryString += ((byte >> i) & 1) ? '1' : '0';
22
+ }
23
+ return binaryString;
24
+ }
25
+ var NONCE_OFFSET = 0xC;
26
+ var NONCE_LENGTH = 8;
27
+ var TAG_LENGTH = 0x10;
28
+ var aes_key = new Uint8Array([0x59, 0xFC, 0x81, 0x7E, 0x64, 0x46, 0xEA, 0x61, 0x90, 0x34, 0x7B, 0x20, 0xE9, 0xBD, 0xCE, 0x52]);
29
+ var pad = new Uint8Array([0,0,0,0]);
30
+ function Uint8Cat(){
31
+ var destLength = 0
32
+ for(var i = 0;i < arguments.length;i++)destLength += arguments[i].length;
33
+ var dest = new Uint8Array(destLength);
34
+ var index = 0;
35
+ for(i = 0;i < arguments.length;i++){
36
+ dest.set(arguments[i],index);
37
+ index += arguments[i].length;
38
+ }
39
+ return dest;
40
+ }
41
+ function decodeAesCcm(data){
42
+ var nonce = Uint8Cat(data.subarray(0,NONCE_LENGTH),pad);
43
+ var ciphertext = data.subarray(NONCE_LENGTH,0x70);
44
+ var plaintext = asmCrypto.AES_CCM.decrypt(ciphertext,aes_key,nonce,undefined,TAG_LENGTH);
45
+ return Uint8Cat(plaintext.subarray(0,NONCE_OFFSET),data.subarray(0,NONCE_LENGTH),plaintext.subarray(NONCE_OFFSET,plaintext.length - 4));
46
+ }
47
+ function crcCalc(data){
48
+ var crc = 0;
49
+ for (var byteIndex = 0;byteIndex < data.length; byteIndex++){
50
+ for (var bitIndex = 7; bitIndex >= 0; bitIndex--){
51
+ crc = (((crc << 1) | ((data[byteIndex] >> bitIndex) & 0x1)) ^
52
+ (((crc & 0x8000) != 0) ? 0x1021 : 0));
53
+ }
54
+ }
55
+ for(var counter = 16; counter > 0; counter--){
56
+ crc = ((crc << 1) ^ (((crc & 0x8000) != 0) ? 0x1021 : 0));
57
+ }
58
+ return(crc & 0xFFFF);
59
+ }
60
+ function encodeAesCcm(data){
61
+ var nonce = Uint8Cat(data.subarray(NONCE_OFFSET,NONCE_OFFSET + NONCE_LENGTH),pad);
62
+ var crcSrc = Uint8Cat(data,new Uint8Array([0,0]));
63
+ var crc = crcCalc(crcSrc);
64
+ var cfsd = Uint8Cat(crcSrc,new Uint8Array([crc >>> 8,crc & 0xff]));
65
+ var plaintext = Uint8Cat(cfsd.subarray(0,NONCE_OFFSET),cfsd.subarray(NONCE_OFFSET + NONCE_LENGTH,cfsd.length),pad,pad);
66
+ var ciphertext = asmCrypto.AES_CCM.encrypt(plaintext,aes_key,nonce,undefined,TAG_LENGTH);
67
+ return Uint8Cat(cfsd.subarray(NONCE_OFFSET,NONCE_OFFSET + NONCE_LENGTH),ciphertext.subarray(0,ciphertext.length - 24),ciphertext.subarray(ciphertext.length - TAG_LENGTH,ciphertext.length))
68
+ }
69
+ function downloadImage(url, filepath) {
70
+ return new Promise((resolve, reject) => {
71
+ httpsLib.get(url, (res) => {
72
+ if (res.statusCode === 200) {
73
+ res.pipe(fs.createWriteStream(filepath))
74
+ .on('error', reject)
75
+ .once('close', () => resolve(filepath));
76
+ } else {
77
+ // Consume response data to free up memory
78
+ res.resume();
79
+ reject(new Error(`Request Failed With a Status Code: ${res.statusCode}`));
80
+
81
+ }
82
+ });
83
+ });
84
+ }
85
+ var wiiCols=["Red","Orange","Yellow","Lime","Green","Blue","Light Blue","Pink","Purple","Brown","White","Black"];
86
+ var wiiFaceFeatures=["None","Blush","Makeup and Blush","Freckles","Bags","Wrinkles on Cheeks","Wrinkles near Eyes","Chin Wrinkle","Makeup","Stubble","Wrinkles near Mouth","Wrinkles"];
87
+ var wiiSkinColors=["White","Tanned White","Darker Skin","Tanned Darker","Mostly Black","Black"];
88
+ var wiiMouthColors=["Peach","Red","Pink"];
89
+ var wiiHairCols=["Black","Dark Brown","Mid Brown","Brown","Grey","Wooden Brown","Dark Blonde","Blonde"];
90
+ var wiiEyeCols=["Black","Grey","Brown","Lime","Blue","Green"];
91
+ var wiiGlassesCols=["Grey","Brown","Red","Blue","Yellow","White"];
92
+ var mouthTable={
93
+ '0': '113',
94
+ '1': '121',
95
+ '2': '231',
96
+ '3': '222',
97
+ '4': '232',
98
+ '5': '132',
99
+ '6': '124',
100
+ '7': '211',
101
+ '8': '123',
102
+ '9': '221',
103
+ '10': '133',
104
+ '11': '223',
105
+ '12': '234',
106
+ '13': '134',
107
+ '14': '224',
108
+ '15': '213',
109
+ '16': '114',
110
+ '17': '212',
111
+ '18': '214',
112
+ '19': '131',
113
+ '20': '233',
114
+ '21': '112',
115
+ '22': '122',
116
+ '23': '111'
117
+ };
118
+ var eyebrowTable={
119
+ '0': '121',
120
+ '1': '112',
121
+ '2': '231',
122
+ '3': '212',
123
+ '4': '134',
124
+ '5': '124',
125
+ '6': '111',
126
+ '7': '113',
127
+ '8': '133',
128
+ '9': '122',
129
+ '10': '221',
130
+ '11': '211',
131
+ '12': '131',
132
+ '13': '223',
133
+ '14': '222',
134
+ '15': '213',
135
+ '16': '224',
136
+ '17': '114',
137
+ '18': '214',
138
+ '19': '132',
139
+ '20': '232',
140
+ '21': '123',
141
+ '22': '233',
142
+ '23': '234'
143
+ };
144
+ var eyeTable={
145
+ '0': '131',
146
+ '1': '113',
147
+ '2': '111',
148
+ '3': '413',
149
+ '4': '121',
150
+ '5': '311',
151
+ '6': '332',
152
+ '7': '411',
153
+ '8': '112',
154
+ '9': '222',
155
+ '10': '414',
156
+ '11': '221',
157
+ '12': '232',
158
+ '13': '331',
159
+ '14': '424',
160
+ '15': '114',
161
+ '16': '133',
162
+ '17': '132',
163
+ '18': '314',
164
+ '19': '231',
165
+ '20': '134',
166
+ '21': '233',
167
+ '22': '433',
168
+ '23': '213',
169
+ '24': '313',
170
+ '25': '214',
171
+ '26': '123',
172
+ '27': '124',
173
+ '28': '324',
174
+ '29': '432',
175
+ '30': '323',
176
+ '31': '333',
177
+ '32': '212',
178
+ '33': '211',
179
+ '34': '223',
180
+ '35': '234',
181
+ '36': '312',
182
+ '37': '322',
183
+ '38': '431',
184
+ '39': '122',
185
+ '40': '224',
186
+ '41': '321',
187
+ '42': '412',
188
+ '43': '423',
189
+ '44': '421',
190
+ '45': '422',
191
+ '46': '334',
192
+ '47': '434'
193
+ };
194
+ var hairTable={
195
+ '0': '534',
196
+ '1': '413',
197
+ '2': '632',
198
+ '3': '521',
199
+ '4': '422',
200
+ '5': '433',
201
+ '6': '522',
202
+ '7': '434',
203
+ '8': '414',
204
+ '9': '612',
205
+ '10': '512',
206
+ '11': '513',
207
+ '12': '411',
208
+ '13': '421',
209
+ '14': '511',
210
+ '15': '624',
211
+ '16': '621',
212
+ '17': '533',
213
+ '18': '622',
214
+ '19': '423',
215
+ '20': '532',
216
+ '21': '524',
217
+ '22': '531',
218
+ '23': '312',
219
+ '24': '614',
220
+ '25': '432',
221
+ '26': '412',
222
+ '27': '424',
223
+ '28': '613',
224
+ '29': '634',
225
+ '30': '314',
226
+ '31': '134',
227
+ '32': '211',
228
+ '33': '111',
229
+ '34': '334',
230
+ '35': '514',
231
+ '36': '313',
232
+ '37': '231',
233
+ '38': '321',
234
+ '39': '122',
235
+ '40': '121',
236
+ '41': '323',
237
+ '42': '331',
238
+ '43': '311',
239
+ '44': '112',
240
+ '45': '113',
241
+ '46': '631',
242
+ '47': '221',
243
+ '48': '212',
244
+ '49': '123',
245
+ '50': '223',
246
+ '51': '131',
247
+ '52': '232',
248
+ '53': '623',
249
+ '54': '332',
250
+ '55': '233',
251
+ '56': '114',
252
+ '57': '324',
253
+ '58': '213',
254
+ '59': '133',
255
+ '60': '224',
256
+ '61': '611',
257
+ '62': '234',
258
+ '63': '523',
259
+ '64': '214',
260
+ '65': '333',
261
+ '66': '222',
262
+ '67': '322',
263
+ '68': '124',
264
+ '69': '431',
265
+ '70': '132',
266
+ '71': '633'
267
+ };
268
+ var cols3DS=["Red","Orange","Yellow","Lime","Green","Blue","Teal","Pink","Purple","Brown","White","Black"];
269
+ var skinCols3DS=["White","Tanned White","Darker White","Tanned Darker","Mostly Black","Black"];
270
+ var faceFeatures3DS=["None","Near Eye Creases","Cheek Creases","Far Eye Creases","Near Nose Creases","Giant Bags","Cleft Chin","Chin Crease","Sunken Eyes","Far Cheek Creases","Lines Near Eyes","Wrinkles"];
271
+ var makeups3DS=["None","Blush","Orange Blush","Blue Eyes","Blush 2","Orange Blush 2","Blue Eyes and Blush","Orange Eyes and Blush","Purple Eyes and Blush 2","Freckles","Beard Stubble","Beard and Mustache Stubble"];
272
+ var eyeCols3DS=["Black","Grey","Brown","Lime","Blue","Green"];
273
+ var hairCols3DS=["Black","Brown","Red","Reddish Brown","Grey","Light Brown","Dark Blonde","Blonde"];
274
+ var mouthCols3DS=["Orange","Red","Pink","Peach","Black"];
275
+ var glassesCols3DS=["Black","Brown","Red","Blue","Yellow","Grey"];
276
+ var tables={
277
+ faces: [
278
+ 0x00,0x01,0x08,
279
+ 0x02,0x03,0x09,
280
+ 0x04,0x05,0x0a,
281
+ 0x06,0x07,0x0b
282
+ ],
283
+ hairs: [
284
+ [0x21,0x2f,0x28,
285
+ 0x25,0x20,0x6b,
286
+ 0x30,0x33,0x37,
287
+ 0x46,0x2c,0x42],
288
+ [0x34,0x32,0x26,
289
+ 0x31,0x2b,0x1f,
290
+ 0x38,0x44,0x3e,
291
+ 0x73,0x4c,0x77],
292
+ [0x40,0x51,0x74,
293
+ 0x79,0x16,0x3a,
294
+ 0x3c,0x57,0x7d,
295
+ 0x75,0x49,0x4b],
296
+ [0x2a,0x59,0x39,
297
+ 0x36,0x50,0x22,
298
+ 0x17,0x56,0x58,
299
+ 0x76,0x27,0x24],
300
+ [0x2d,0x43,0x3b,
301
+ 0x41,0x29,0x1e,
302
+ 0x0c,0x10,0x0a,
303
+ 0x52,0x80,0x81],
304
+ [0x0e,0x5f,0x69,
305
+ 0x64,0x06,0x14,
306
+ 0x5d,0x66,0x1b,
307
+ 0x04,0x11,0x6e],
308
+ [0x7b,0x08,0x6a,
309
+ 0x48,0x03,0x15,
310
+ 0x00,0x62,0x3f,
311
+ 0x5a,0x0b,0x78],
312
+ [0x05,0x4a,0x6c,
313
+ 0x5e,0x7c,0x19,
314
+ 0x63,0x45,0x23,
315
+ 0x0d,0x7a,0x71],
316
+ [0x35,0x18,0x55,
317
+ 0x53,0x47,0x83,
318
+ 0x60,0x65,0x1d,
319
+ 0x07,0x0f,0x70],
320
+ [0x4f,0x01,0x6d,
321
+ 0x7f,0x5b,0x1a,
322
+ 0x3d,0x67,0x02,
323
+ 0x4d,0x12,0x5c],
324
+ [0x54,0x09,0x13,
325
+ 0x82,0x61,0x68,
326
+ 0x2e,0x4e,0x1c,
327
+ 0x72,0x7e,0x6f]
328
+ ],
329
+ eyebrows: [
330
+ [0x06,0x00,0x0c,
331
+ 0x01,0x09,0x13,
332
+ 0x07,0x15,0x08,
333
+ 0x11,0x05,0x04],
334
+ [0x0b,0x0a,0x02,
335
+ 0x03,0x0e,0x14,
336
+ 0x0f,0x0d,0x16,
337
+ 0x12,0x10,0x17]
338
+ ],
339
+ eyes: [
340
+ [0x02,0x04,0x00,
341
+ 0x08,0x27,0x11,
342
+ 0x01,0x1a,0x10,
343
+ 0x0f,0x1b,0x14],
344
+ [0x21,0x0b,0x13,
345
+ 0x20,0x09,0x0c,
346
+ 0x17,0x22,0x15,
347
+ 0x19,0x28,0x23],
348
+ [0x05,0x29,0x0d,
349
+ 0x24,0x25,0x06,
350
+ 0x18,0x1e,0x1f,
351
+ 0x12,0x1c,0x2e],
352
+ [0x07,0x2c,0x26,
353
+ 0x2a,0x2d,0x1d,
354
+ 0x03,0x2b,0x16,
355
+ 0x0a,0x0e,0x2f],
356
+ [0x30,0x31,0x32,
357
+ 0x35,0x3b,0x38,
358
+ 0x36,0x3a,0x39,
359
+ 0x37,0x33,0x34]
360
+ ],
361
+ noses: [
362
+ [0x01,0x0a,0x02,
363
+ 0x03,0x06,0x00,
364
+ 0x05,0x04,0x08,
365
+ 0x09,0x07,0x0B],
366
+ [0x0d,0x0e,0x0c,
367
+ 0x11,0x10,0x0f]
368
+ ],
369
+ mouths: [
370
+ [0x17,0x01,0x13,
371
+ 0x15,0x16,0x05,
372
+ 0x00,0x08,0x0a,
373
+ 0x10,0x06,0x0d],
374
+ [0x07,0x09,0x02,
375
+ 0x11,0x03,0x04,
376
+ 0x0f,0x0b,0x14,
377
+ 0x12,0x0e,0x0c],
378
+ [0x1b,0x1e,0x18,
379
+ 0x19,0x1d,0x1c,
380
+ 0x1a,0x23,0x1f,
381
+ 0x22,0x21,0x20]
382
+ ]
383
+ };
384
+ function lookupTable(table,value,paginated){
385
+ if(paginated){
386
+ for(var i=0;i<tables[table].length;i++){
387
+ for(var j=0;j<tables[table][i].length;j++){
388
+ if(tables[table][i][j]===value){
389
+ return [i,j];
390
+ }
391
+ }
392
+ }
393
+ }
394
+ else{
395
+ for(var i=0;i<tables[table].length;i++){
396
+ if(tables[table][i]===value){
397
+ return i;
398
+ }
399
+ }
400
+ }
401
+ return undefined;
402
+ }
403
+ module.exports={
404
+ readWiiBin:function(binPath){
405
+ var thisMii={
406
+ info:{},
407
+ face:{},
408
+ nose:{},
409
+ mouth:{},
410
+ mole:{},
411
+ hair:{},
412
+ eyebrows:{},
413
+ eyes:{},
414
+ glasses:{},
415
+ facialHair:{}
416
+ };
417
+ binary = fs.readFileSync(binPath);
418
+ var name="";
419
+ for(var i=0;i<10;i++){
420
+ name+=binary.slice(3+i*2, 4+i*2)+"";
421
+ }
422
+ thisMii.name=name.replaceAll("\x00","");
423
+ var cname="";
424
+ for(var i=0;i<10;i++){
425
+ cname+=binary.slice(55+i*2, 56+i*2)+"";
426
+ }
427
+ thisMii.creatorName=cname.replaceAll("\x00","");
428
+ thisMii.info.creatorName=thisMii.creatorName;
429
+ thisMii.info.name=thisMii.name;//Up to ten characters
430
+ thisMii.info.gender=getBinaryFromAddress(0x00)[1]==="1"?"Female":"Male";//0 for Male, 1 for Female
431
+ thisMii.info.miiId=parseInt(getBinaryFromAddress(0x18),2).toString(16)+parseInt(getBinaryFromAddress(0x19),2).toString(16)+parseInt(getBinaryFromAddress(0x1A),2).toString(16)+parseInt(getBinaryFromAddress(0x1B),2).toString(16);
432
+ thisMii.info.systemId=parseInt(getBinaryFromAddress(0x1C),2).toString(16)+parseInt(getBinaryFromAddress(0x1D),2).toString(16)+parseInt(getBinaryFromAddress(0x1E),2).toString(16)+parseInt(getBinaryFromAddress(0x1F),2).toString(16);
433
+ var temp=getBinaryFromAddress(0x20);
434
+ thisMii.face.shape=parseInt(temp.slice(0,3),2);//0-7
435
+ thisMii.face.col=wiiSkinColors[parseInt(temp.slice(3,6),2)];//0-5
436
+ temp=getBinaryFromAddress(0x21);
437
+ thisMii.face.feature=wiiFaceFeatures[parseInt(getBinaryFromAddress(0x20).slice(6,8)+temp.slice(0,2),2)];//0-11
438
+ thisMii.info.mingle=temp[5]==="1"?false:true;//0 for Mingle, 1 for Don't Mingle
439
+ temp=getBinaryFromAddress(0x2C);
440
+ thisMii.nose.type=parseInt(temp.slice(0,4),2);//Needs lookup table
441
+ thisMii.nose.size=parseInt(temp.slice(4,8),2);
442
+ thisMii.nose.vertPos=parseInt(getBinaryFromAddress(0x2D).slice(0,5),2);//From top to bottom, 0-18, default 9
443
+ temp=getBinaryFromAddress(0x2E);
444
+ thisMii.mouth.type=mouthTable[""+parseInt(temp.slice(0,5),2)];//0-23, Needs lookup table
445
+ thisMii.mouth.col=wiiMouthColors[parseInt(temp.slice(5,7),2)];//0-2, refer to mouthColors array
446
+ temp2=getBinaryFromAddress(0x2F);
447
+ thisMii.mouth.size=parseInt(temp[7]+temp2.slice(0,3),2);//0-8, default 4
448
+ thisMii.mouth.yPos=parseInt(temp2.slice(3,8),2);//0-18, default 9, from top to bottom
449
+ temp=getBinaryFromAddress(0x00);
450
+ var temp2=getBinaryFromAddress(0x01);
451
+ thisMii.info.birthMonth=parseInt(temp.slice(2,6),2);
452
+ thisMii.info.birthday=parseInt(temp.slice(6,8)+temp2.slice(0,3),2);
453
+ thisMii.info.favColor=wiiCols[parseInt(temp2.slice(3,7),2)];//0-11, refer to cols array
454
+ thisMii.info.favorited=temp2[7]==="0"?false:true;
455
+ thisMii.info.height=parseInt(getBinaryFromAddress(0x16),2);//0-127
456
+ thisMii.info.weight=parseInt(getBinaryFromAddress(0x17),2);//0-127
457
+ thisMii.info.downloadedFromCheckMiiOut=getBinaryFromAddress(0x21)[7]==="0"?false:true;
458
+ temp=getBinaryFromAddress(0x34);
459
+ temp2=getBinaryFromAddress(0x35);
460
+ thisMii.mole.on=temp[0]==="0"?false:true;//0 for Off, 1 for On
461
+ thisMii.mole.size=parseInt(temp.slice(1,5),2);//0-8, default 4
462
+ thisMii.mole.xPos=parseInt(temp2.slice(2,7),2);//0-16, Default 2
463
+ thisMii.mole.yPos=parseInt(temp.slice(5,8)+temp2.slice(0,2),2);//Top to bottom
464
+ temp=getBinaryFromAddress(0x22);
465
+ temp2=getBinaryFromAddress(0x23);
466
+ thisMii.hair.type=hairTable[""+parseInt(temp.slice(0,7),2)];//0-71, Needs lookup table
467
+ thisMii.hair.col=wiiHairCols[parseInt(temp[7]+temp2.slice(0,2),2)];//0-7, refer to hairCols array
468
+ thisMii.hair.flipped=temp2[2]==="0"?false:true;
469
+ temp=getBinaryFromAddress(0x24);
470
+ temp2=getBinaryFromAddress(0x25);
471
+ thisMii.eyebrows.type=eyebrowTable[""+parseInt(temp.slice(0,5),2)];//0-23, Needs lookup table
472
+ thisMii.eyebrows.rotation=parseInt(temp.slice(6,8)+temp2.slice(0,2),2);//0-11, default varies based on eyebrow type
473
+ temp=getBinaryFromAddress(0x26);
474
+ temp2=getBinaryFromAddress(0x27);
475
+ thisMii.eyebrows.col=wiiHairCols[parseInt(temp.slice(0,3),2)];
476
+ thisMii.eyebrows.size=parseInt(temp.slice(3,7),2);//0-8, default 4
477
+ thisMii.eyebrows.yPos=parseInt(temp[7]+temp2.slice(0,4),2);//0-18, default 10
478
+ thisMii.eyebrows.distApart=parseInt(temp2.slice(4,8),2);//0-12, default 2
479
+ thisMii.eyes.type=eyeTable[parseInt(getBinaryFromAddress(0x28).slice(0,6),2)];//0-47, needs lookup table
480
+ temp=getBinaryFromAddress(0x29);
481
+ thisMii.eyes.rotation=parseInt(temp.slice(0,3),2);//0-7, default varies based on eye type
482
+ thisMii.eyes.yPos=parseInt(temp.slice(3,8),2);//0-18, default 12, top to bottom
483
+ temp=getBinaryFromAddress(0x2A);
484
+ thisMii.eyes.col=wiiEyeCols[parseInt(temp.slice(0,3),2)];//0-5
485
+ thisMii.eyes.size=parseInt(temp.slice(4,7),2);//0-7, default 4
486
+ temp2=getBinaryFromAddress(0x2B);
487
+ thisMii.eyes.distApart=parseInt(temp[7]+temp2.slice(0,3),2);//0-12, default 2
488
+ temp=getBinaryFromAddress(0x30);
489
+ thisMii.glasses.type=parseInt(temp.slice(0,4),2);//0-8
490
+ thisMii.glasses.col=wiiGlassesCols[parseInt(temp.slice(4,7),2)];//0-5
491
+ temp=getBinaryFromAddress(0x31);
492
+ thisMii.glasses.size=parseInt(temp.slice(0,3),2);//0-7, default 4
493
+ thisMii.glasses.yPos=parseInt(temp.slice(3,8),2);//0-20, default 10
494
+ temp=getBinaryFromAddress(0x32);
495
+ temp2=getBinaryFromAddress(0x33);
496
+ thisMii.facialHair.mustacheType=parseInt(temp.slice(0,2),2);//0-3
497
+ thisMii.facialHair.beardType=parseInt(temp.slice(2,4),2);//0-3
498
+ thisMii.facialHair.col=wiiHairCols[parseInt(temp.slice(4,7),2)];//0-7
499
+ thisMii.facialHair.mustacheSize=parseInt(temp[7]+temp2.slice(0,3),2);//0-30, default 20
500
+ thisMii.facialHair.mustacheYPos=parseInt(temp2.slice(3,8),2);//0-16, default 2
501
+ return thisMii;
502
+ },
503
+ read3DSQR:async function(qrPath){
504
+ function readMii(){
505
+ var miiJson={
506
+ info:{},
507
+ perms:{},
508
+ hair:{},
509
+ face:{},
510
+ eyes:{},
511
+ eyebrows:{},
512
+ nose:{},
513
+ mouth:{},
514
+ facialHair:{},
515
+ glasses:{},
516
+ mole:{}
517
+ };
518
+ binary=fs.readFileSync("./decryptedTemp.3dMii");
519
+ var temp=getBinaryFromAddress(0x18);
520
+ var temp2=getBinaryFromAddress(0x19);
521
+ miiJson.info.birthday=parseInt(temp2.slice(6,8)+temp.slice(0,3),2);
522
+ miiJson.info.birthMonth=parseInt(temp.slice(3,7),2);
523
+ var name="";
524
+ for(var i=0x1A;i<0x2E;i++){
525
+ name+=binary.slice(i,i+1);
526
+ }
527
+ miiJson.name=name.replaceAll("\x00","");
528
+ var cname="";
529
+ for(var i=0x48;i<0x5C;i++){
530
+ cname+=binary.slice(i,i+1);
531
+ }
532
+ miiJson.creatorName=cname.replaceAll("\x00","");
533
+ miiJson.info.name=miiJson.name;
534
+ miiJson.info.creatorName=miiJson.creatorName;
535
+ miiJson.info.height=parseInt(getBinaryFromAddress(0x2E),2);
536
+ miiJson.info.weight=parseInt(getBinaryFromAddress(0x2F),2);
537
+ miiJson.info.gender=temp[7]==="1"?"Female":"Male";
538
+ temp=getBinaryFromAddress(0x30);
539
+ miiJson.perms.sharing=temp[7]==="1"?false:true;
540
+ miiJson.info.favColor=cols3DS[parseInt(temp2.slice(2,6),2)];
541
+ miiJson.perms.copying=getBinaryFromAddress(0x01)[7]==="1"?true:false;
542
+ miiJson.hair.style=lookupTable("hairs",parseInt(getBinaryFromAddress(0x32),2),true);
543
+ miiJson.face.shape=lookupTable("faces",parseInt(temp.slice(3,7),2),false);
544
+ miiJson.face.col=skinCols3DS[parseInt(temp.slice(0,3),2)];
545
+ temp=getBinaryFromAddress(0x31);
546
+ miiJson.face.feature=faceFeatures3DS[parseInt(temp.slice(4,8),2)];
547
+ miiJson.face.makeup=makeups3DS[parseInt(temp.slice(0,4),2)];
548
+ temp=getBinaryFromAddress(0x34);
549
+ miiJson.eyes.type=lookupTable("eyes",parseInt(temp.slice(2,8),2),true);
550
+ temp2=getBinaryFromAddress(0x33);
551
+ miiJson.hair.col=hairCols3DS[parseInt(temp2.slice(5,8),2)];
552
+ miiJson.hair.flipped=temp2[4]==="0"?false:true;
553
+ miiJson.eyes.col=eyeCols3DS[parseInt(getBinaryFromAddress(0x35)[7]+temp.slice(0,2),2)];
554
+ temp=getBinaryFromAddress(0x35);
555
+ miiJson.eyes.size=parseInt(temp.slice(3,7),2);
556
+ miiJson.eyes.squash=parseInt(temp.slice(0,3),2);
557
+ temp=getBinaryFromAddress(0x36);
558
+ temp2=getBinaryFromAddress(0x37);
559
+ miiJson.eyes.rot=parseInt(temp.slice(3,8),2);
560
+ miiJson.eyes.distApart=parseInt(temp2[7]+temp.slice(0,3),2);
561
+ miiJson.eyes.yPos=parseInt(temp2.slice(2,7),2);
562
+ temp=getBinaryFromAddress(0x38);
563
+ miiJson.eyebrows.style=lookupTable("eyebrows",parseInt(temp.slice(3,8),2),true);
564
+ miiJson.eyebrows.col=hairCols3DS[parseInt(temp.slice(0,3),2)];
565
+ temp=getBinaryFromAddress(0x39);
566
+ miiJson.eyebrows.size=parseInt(temp.slice(4,8),2);
567
+ miiJson.eyebrows.squash=parseInt(temp.slice(1,4),2);
568
+ temp=getBinaryFromAddress(0x3A);
569
+ miiJson.eyebrows.rot=parseInt(temp.slice(4,8),2);
570
+ temp2=getBinaryFromAddress(0x3B);
571
+ miiJson.eyebrows.distApart=parseInt(temp2[7]+temp.slice(0,3),2);
572
+ miiJson.eyebrows.yPos=parseInt(temp2.slice(2,7),2)-3;
573
+ temp=getBinaryFromAddress(0x3C);
574
+ miiJson.nose.type=lookupTable("noses",parseInt(temp.slice(3,8),2),true);
575
+ temp2=getBinaryFromAddress(0x3D);
576
+ miiJson.nose.size=parseInt(temp2[7]+temp.slice(0,3),2);
577
+ miiJson.nose.yPos=parseInt(temp2.slice(2,7),2);
578
+ temp=getBinaryFromAddress(0x3E);
579
+ miiJson.mouth.type=lookupTable("mouths",parseInt(temp.slice(2,8),2),true);
580
+ temp2=getBinaryFromAddress(0x3F);
581
+ miiJson.mouth.col=mouthCols3DS[parseInt(temp2[7]+temp.slice(0,2),2)];
582
+ miiJson.mouth.size=parseInt(temp2.slice(3,7),2);
583
+ miiJson.mouth.squash=parseInt(temp2.slice(0,3),2);
584
+ temp=getBinaryFromAddress(0x40);
585
+ miiJson.mouth.yPos=parseInt(temp.slice(3,8),2);
586
+ miiJson.facialHair.mustacheType=parseInt(temp.slice(0,3),2);
587
+ temp=getBinaryFromAddress(0x42);
588
+ miiJson.facialHair.beardType=parseInt(temp.slice(5,8),2);
589
+ miiJson.facialHair.col=hairCols3DS[parseInt(temp.slice(2,5),2)];
590
+ temp2=getBinaryFromAddress(0x43);
591
+ miiJson.facialHair.mustacheSize=parseInt(temp2.slice(6,8)+temp.slice(0,2),2);
592
+ miiJson.facialHair.mustacheYPos=parseInt(temp2.slice(1,6),2);
593
+ temp=getBinaryFromAddress(0x44);
594
+ miiJson.glasses.type=parseInt(temp.slice(4,8),2);
595
+ miiJson.glasses.col=glassesCols3DS[parseInt(temp.slice(1,4),2)];
596
+ temp2=getBinaryFromAddress(0x45);
597
+ miiJson.glasses.size=parseInt(temp2.slice(5,8)+temp[0],2);
598
+ miiJson.glasses.yPos=parseInt(temp2.slice(1,5),2);
599
+ temp=getBinaryFromAddress(0x46);
600
+ miiJson.mole.on=temp[7]==="0"?false:true;
601
+ miiJson.mole.size=parseInt(temp.slice(3,7),2);
602
+ temp2=getBinaryFromAddress(0x47);
603
+ miiJson.mole.xPos=parseInt(temp2.slice(6,8)+temp.slice(0,3),2);
604
+ miiJson.mole.yPos=parseInt(temp2.slice(1,6),2);
605
+ fs.unlinkSync("./decryptedTemp.3dmii");
606
+ fs.unlinkSync("./encryptedTemp.3dmii");
607
+ return miiJson;
608
+ }
609
+ var data=fs.readFileSync(qrPath);
610
+ var img=await loadImage(data);
611
+ const canvas = createCanvas(img.width, img.height);
612
+ const ctx = canvas.getContext('2d');
613
+ ctx.drawImage(img, 0, 0);
614
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
615
+ const qrCode = jsQR(imageData.data, imageData.width, imageData.height);
616
+
617
+ if (qrCode) {
618
+ fs.writeFileSync("./encryptedTemp.3dMii",Buffer.from(qrCode.binaryData));
619
+ var data = decodeAesCcm(new Uint8Array(qrCode.binaryData));
620
+ fs.writeFileSync("./decryptedTemp.3dMii",Buffer.from(data));
621
+ return Promise.resolve(readMii());
622
+ } else {
623
+ console.error('Failed to decode QR code');
624
+ }
625
+ },
626
+ writeWiiBin:function(jsonIn,outPath){
627
+ var mii=jsonIn;
628
+ var miiBin="0";
629
+ miiBin+=mii.info.gender==="Male"?"0":"1";
630
+ miiBin+=mii.info.birthMonth.toString(2).padStart(4,"0");
631
+ miiBin+=mii.info.birthday.toString(2).padStart(5,"0");
632
+ miiBin+=wiiCols.indexOf(mii.info.favColor).toString(2).padStart(4,"0");
633
+ miiBin+=mii.info.favorited?1:0;
634
+ for(var i=0;i<10;i++){
635
+ miiBin+="00000000";
636
+ if(i<mii.name.length){
637
+ miiBin+=mii.name.charCodeAt(i).toString(2).padStart(8,"0");
638
+ }
639
+ else{
640
+ miiBin+="00000000";
641
+ }
642
+ }
643
+ miiBin+=mii.info.height.toString(2).padStart(8,"0");
644
+ miiBin+=mii.info.weight.toString(2).padStart(8,"0");
645
+ let miiId="";
646
+ switch(mii.info.type){
647
+ case "Special":
648
+ miiId="01000110";
649
+ break;
650
+ case "Foreign":
651
+ miiId="11000110";
652
+ break;
653
+ default:
654
+ miiId="10101001";
655
+ break;
656
+ }
657
+ for(var i=0;i<3;i++){
658
+ miiId+=Math.floor(Math.random()*255).toString(2).padStart(8,"0");
659
+ }
660
+ miiBin+=miiId;
661
+ miiBin+="11111111".repeat(4);//System ID
662
+ miiBin+=mii.face.shape.toString(2).padStart(3,"0");
663
+ miiBin+=wiiSkinColors.indexOf(mii.face.col).toString(2).padStart(3,"0");
664
+ miiBin+=wiiFaceFeatures.indexOf(mii.face.feature).toString(2).padStart(4,"0");
665
+ miiBin+="000";
666
+ if(mii.info.mingle&&mii.info.type==="Special"){
667
+ console.error("A Special Mii cannot have Mingle on and still render on the Wii. Turned Mingle off in the output file.");
668
+ }
669
+ miiBin+=mii.info.mingle?"0":"1";
670
+ miiBin+="0";
671
+ miiBin+=mii.info.downloadedFromCheckMiiOut?"1":"0";
672
+ miiBin+=(+getKeyByValue(hairTable,mii.hair.type)).toString(2).padStart(7,"0");
673
+ miiBin+=wiiHairCols.indexOf(mii.hair.col).toString(2).padStart(3,"0");
674
+ miiBin+=mii.hair.flipped?"1":"0";
675
+ miiBin+="00000";
676
+ miiBin+=(+getKeyByValue(eyebrowTable,mii.eyebrows.type)).toString(2).padStart(5,"0");
677
+ miiBin+="0";
678
+ miiBin+=mii.eyebrows.rotation.toString(2).padStart(4,"0");
679
+ miiBin+="000000";
680
+ miiBin+=wiiHairCols.indexOf(mii.eyebrows.col).toString(2).padStart(3,"0");
681
+ miiBin+=mii.eyebrows.size.toString(2).padStart(4,"0");
682
+ miiBin+=mii.eyebrows.yPos.toString(2).padStart(5,"0");
683
+ miiBin+=mii.eyebrows.distApart.toString(2).padStart(4,"0");
684
+ miiBin+=(+getKeyByValue(eyeTable,mii.eyes.type)).toString(2).padStart(6,"0");
685
+ miiBin+="00";
686
+ miiBin+=mii.eyes.rotation.toString(2).padStart(3,"0");
687
+ miiBin+=mii.eyes.yPos.toString(2).padStart(5,"0");
688
+ miiBin+=wiiEyeCols.indexOf(mii.eyes.col).toString(2).padStart(3,"0");
689
+ miiBin+="0";
690
+ miiBin+=mii.eyes.size.toString(2).padStart(3,"0");
691
+ miiBin+=mii.eyes.distApart.toString(2).padStart(4,"0");
692
+ miiBin+="00000";
693
+ miiBin+=mii.nose.type.toString(2).padStart(4,"0");
694
+ miiBin+=mii.nose.size.toString(2).padStart(4,"0");
695
+ miiBin+=mii.nose.vertPos.toString(2).padStart(5,"0");
696
+ miiBin+="000";
697
+ miiBin+=(+getKeyByValue(mouthTable,mii.mouth.type)).toString(2).padStart(5,"0");
698
+ miiBin+=wiiMouthColors.indexOf(mii.mouth.col).toString(2).padStart(2,"0");
699
+ miiBin+=mii.mouth.size.toString(2).padStart(4,"0");
700
+ miiBin+=mii.mouth.yPos.toString(2).padStart(5,"0");
701
+ miiBin+=mii.glasses.type.toString(2).padStart(4,"0");
702
+ miiBin+=wiiGlassesCols.indexOf(mii.glasses.col).toString(2).padStart(3,"0");
703
+ miiBin+="0";
704
+ miiBin+=mii.glasses.size.toString(2).padStart(3,"0");
705
+ miiBin+=mii.glasses.yPos.toString(2).padStart(5,"0");
706
+ miiBin+=mii.facialHair.mustacheType.toString(2).padStart(2,"0");
707
+ miiBin+=mii.facialHair.beardType.toString(2).padStart(2,"0");
708
+ miiBin+=wiiHairCols.indexOf(mii.facialHair.col).toString(2).padStart(3,"0");
709
+ miiBin+=mii.facialHair.mustacheSize.toString(2).padStart(4,"0");
710
+ miiBin+=mii.facialHair.mustacheYPos.toString(2).padStart(5,"0");
711
+ miiBin+=mii.mole.on?"1":"0";
712
+ miiBin+=mii.mole.size.toString(2).padStart(4,"0");
713
+ miiBin+=mii.mole.yPos.toString(2).padStart(5,"0");
714
+ miiBin+=mii.mole.xPos.toString(2).padStart(5,"0");
715
+ miiBin+="0";
716
+ for(var i=0;i<10;i++){
717
+ miiBin+="00000000";
718
+ if(i<mii.creatorName.length){
719
+ miiBin+=mii.creatorName.charCodeAt(i).toString(2).padStart(8,"0");
720
+ }
721
+ else{
722
+ miiBin+="00000000";
723
+ }
724
+ }
725
+
726
+ //Writing based on miiBin
727
+ var toWrite=miiBin.match(/.{1,8}/g);
728
+ var buffers=[];
729
+ for(var i=0;i<toWrite.length;i++){
730
+ buffers.push(parseInt(toWrite[i],2));
731
+ }
732
+ const buffer = Buffer.from(buffers);
733
+ fs.writeFileSync(outPath, buffer);
734
+ },
735
+ write3DSQR:function(jsonIn,outPath){
736
+ var mii=jsonIn;
737
+ function makeMiiBinary(mii){
738
+ if(mii.perms.sharing&&mii.info.type==="Special"){
739
+ mii.perms.sharing=false;
740
+ console.log("Cannot have Sharing enabled for Special Miis. Disabled Sharing.");
741
+ }
742
+ var miiBin="00000011";
743
+ miiBin+="0000000";
744
+ miiBin+=mii.perms.copying?"1":"0";
745
+ miiBin+="00000000";
746
+ miiBin+="00110000";
747
+ miiBin+="1000101011010010000001101000011100011000110001100100011001100110010101100111111110111100000001110101110001000101011101100000001110100100010000000000000000000000".slice(0,8*8);
748
+ miiBin+=mii.info.type==="Special"?"0":"1";
749
+ miiBin+="0000000";
750
+ miiBin+="0111111110111100000001110101110001000101011101100000001110100100010000000000000000000000";
751
+ miiBin+=mii.info.birthday.toString(2).padStart(5,"0").slice(2,5);
752
+ miiBin+=mii.info.birthMonth.toString(2).padStart(4,"0");
753
+ miiBin+=mii.info.gender==="Male"?"0":"1";
754
+ miiBin+="00";
755
+ miiBin+=cols3DS.indexOf(mii.info.favColor).toString(2).padStart(4,"0");
756
+ miiBin+=mii.info.birthday.toString(2).padStart(5,"0").slice(0,2);
757
+ for(var i=0;i<10;i++){
758
+ if(i<mii.name.length){
759
+ miiBin+=mii.name.charCodeAt(i).toString(2).padStart(8,"0");
760
+ }
761
+ else{
762
+ miiBin+="00000000";
763
+ }
764
+ miiBin+="00000000";
765
+ }
766
+ miiBin+=mii.info.height.toString(2).padStart(8,"0");
767
+ miiBin+=mii.info.weight.toString(2).padStart(8,"0");
768
+ miiBin+=skinCols3DS.indexOf(mii.face.col).toString(2).padStart(3,"0");
769
+ miiBin+=tables.faces[mii.face.shape].toString(2).padStart(4,"0");
770
+ miiBin+=mii.perms.sharing?"0":"1";
771
+ miiBin+=makeups3DS.indexOf(mii.face.makeup).toString(2).padStart(4,"0");
772
+ miiBin+=faceFeatures3DS.indexOf(mii.face.feature).toString(2).padStart(4,"0");
773
+ miiBin+=tables.hairs[mii.hair.style[0]][mii.hair.style[1]].toString(2).padStart(8,"0");
774
+ miiBin+="0000";
775
+ miiBin+=mii.hair.flipped?"1":"0";
776
+ miiBin+=hairCols3DS.indexOf(mii.hair.col).toString(2).padStart(3,"0");
777
+ miiBin+=eyeCols3DS.indexOf(mii.eyes.col).toString(2).padStart(3,"0").slice(1,3);
778
+ miiBin+=tables.eyes[mii.eyes.type[0]][mii.eyes.type[1]].toString(2).padStart(6,"0");
779
+ miiBin+=mii.eyes.squash.toString(2).padStart(3,"0");
780
+ miiBin+=mii.eyes.size.toString(2).padStart(4,"0");
781
+ miiBin+=eyeCols3DS.indexOf(mii.eyes.col).toString(2).padStart(3,"0")[0];
782
+ miiBin+=mii.eyes.distApart.toString(2).padStart(4,"0").slice(1,4);
783
+ miiBin+=mii.eyes.rot.toString(2).padStart(5,"0");
784
+ miiBin+="00";
785
+ miiBin+=mii.eyes.yPos.toString(2).padStart(5,"0");
786
+ miiBin+=mii.eyes.distApart.toString(2).padStart(4,"0")[0];
787
+ miiBin+=hairCols3DS.indexOf(mii.eyebrows.col).toString(2).padStart(3,"0");
788
+ miiBin+=tables.eyebrows[mii.eyebrows.style[0]][mii.eyebrows.style[1]].toString(2).padStart(5,"0");
789
+ miiBin+="0";
790
+ miiBin+=mii.eyebrows.squash.toString(2).padStart(3,"0");
791
+ miiBin+=mii.eyebrows.size.toString(2).padStart(4,"0");
792
+ miiBin+=mii.eyebrows.distApart.toString(2).padStart(4,"0").slice(1,4);
793
+ miiBin+="0";
794
+ miiBin+=mii.eyebrows.rot.toString(2).padStart(4,"0");
795
+ miiBin+="00";
796
+ miiBin+=(mii.eyebrows.yPos+3).toString(2).padStart(5,"0");
797
+ miiBin+=mii.eyebrows.distApart.toString(2).padStart(4,"0")[0];
798
+ miiBin+=mii.nose.size.toString(2).padStart(4,"0").slice(1,4);
799
+ miiBin+=tables.noses[mii.nose.type[0]][mii.nose.type[1]].toString(2).padStart(5,"0");
800
+ miiBin+="00";
801
+ miiBin+=mii.nose.yPos.toString(2).padStart(5,"0");
802
+ miiBin+=mii.nose.size.toString(2).padStart(4,"0")[0];
803
+ miiBin+=mouthCols3DS.indexOf(mii.mouth.col).toString(2).padStart(3,"0").slice(1,3);
804
+ miiBin+=tables.mouths[mii.mouth.type[0]][mii.mouth.type[1]].toString(2).padStart(6,"0");
805
+ miiBin+=mii.mouth.squash.toString(2).padStart(3,"0");
806
+ miiBin+=mii.mouth.size.toString(2).padStart(4,"0");
807
+ miiBin+=mouthCols3DS.indexOf(mii.mouth.col).toString(2).padStart(3,"0")[0];
808
+ miiBin+=mii.facialHair.mustacheType.toString(2).padStart(3,"0");
809
+ miiBin+=mii.mouth.yPos.toString(2).padStart(5,"0");
810
+ miiBin+="00000000";
811
+ miiBin+=mii.facialHair.mustacheSize.toString(2).padStart(4,"0").slice(2,4);
812
+ miiBin+=hairCols3DS.indexOf(mii.facialHair.col).toString(2).padStart(3,"0");
813
+ miiBin+=mii.facialHair.beardType.toString(2).padStart(3,"0");
814
+ miiBin+="0";
815
+ miiBin+=mii.facialHair.mustacheYPos.toString(2).padStart(5,"0");
816
+ miiBin+=mii.facialHair.mustacheSize.toString(2).padStart(4,"0").slice(0,2);
817
+ miiBin+=mii.glasses.size.toString(2).padStart(4,"0")[3];
818
+ miiBin+=glassesCols3DS.indexOf(mii.glasses.col).toString(2).padStart(3,"0");
819
+ miiBin+=mii.glasses.type.toString(2).padStart(4,"0");
820
+ miiBin+="0";
821
+ miiBin+=mii.glasses.yPos.toString(2).padStart(4,"0");
822
+ miiBin+=mii.glasses.size.toString(2).padStart(4,"0").slice(0,3);
823
+ miiBin+=mii.mole.xPos.toString(2).padStart(5,"0").slice(2,5);
824
+ miiBin+=mii.mole.size.toString(2).padStart(4,"0");
825
+ miiBin+=mii.mole.on?"1":"0";
826
+ miiBin+="0";
827
+ miiBin+=mii.mole.yPos.toString(2).padStart(5,"0");
828
+ miiBin+=mii.mole.xPos.toString(2).padStart(5,"0").slice(0,2);
829
+ for(var i=0;i<10;i++){
830
+ if(i<mii.creatorName.length){
831
+ miiBin+=mii.creatorName.charCodeAt(i).toString(2).padStart(8,"0");
832
+ }
833
+ else{
834
+ miiBin+="00000000";
835
+ }
836
+ miiBin+="00000000";
837
+ }
838
+ //Writing based on miiBin
839
+ var toWrite=miiBin.match(/.{1,8}/g);
840
+ var buffers=[];
841
+ for(var i=0;i<toWrite.length;i++){
842
+ buffers.push(parseInt(toWrite[i],2));
843
+ }
844
+ const buffer = Buffer.from(buffers);
845
+ fs.writeFileSync(outPath, buffer);
846
+ }
847
+ makeMiiBinary(mii);
848
+ var encryptedData = Buffer.from(encodeAesCcm(new Uint8Array(fs.readFileSync(outPath))));
849
+ fs.writeFileSync(outPath,encryptedData);
850
+ QRCode.toFile('./'+mii.name+'Output.png', [{ data: fs.readFileSync(outPath), mode: 'byte' }], {type: 'png'}, function (err) {
851
+ if (err) throw err;
852
+ });
853
+ var studioMii=new Uint8Array([0x08, 0x00, 0x40, 0x03, 0x08, 0x04, 0x04, 0x02, 0x02, 0x0c, 0x03, 0x01, 0x06, 0x04, 0x06, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x04, 0x00, 0x0a, 0x01, 0x00, 0x21, 0x40, 0x04, 0x00, 0x02, 0x14, 0x03, 0x13, 0x04, 0x17, 0x0d, 0x04, 0x00, 0x0a, 0x04, 0x01, 0x09]);
854
+ //miiPreview.src = 'https://studio.mii.nintendo.com/miis/image.png?data=' + mii.previewData + "&width=270&type=face";
855
+ function encodeStudio(studio) {
856
+ function byteToString(int){
857
+ var str = int.toString(16);
858
+ if(str.length < 2)str = '0' + str;
859
+ return str;
860
+ }
861
+ var n = 0;
862
+ var eo;
863
+ var dest = byteToString(n);
864
+ for (var i = 0; i < studio.length; i++) {
865
+ eo = (7 + (studio[i] ^ n)) & 0xFF;
866
+ n = eo;
867
+ dest += byteToString(eo);
868
+ }
869
+ return dest;
870
+ }
871
+ studioMii[0x16] = mii.info.gender==="Male"?0:1;
872
+ studioMii[0x15] = cols3DS.indexOf(mii.info.favColor);
873
+ studioMii[0x1E] = mii.info.height;
874
+ studioMii[2] = mii.info.weight;
875
+ studioMii[0x13] = tables.faces[mii.face.shape];
876
+ studioMii[0x11] = skinCols3DS.indexOf(mii.face.col);
877
+ studioMii[0x14] = faceFeatures3DS.indexOf(mii.face.feature);
878
+ studioMii[0x12] = makeups3DS.indexOf(mii.face.makeup);
879
+ studioMii[0x1D] = tables.hairs[mii.hair.style[0]][mii.hair.style[1]];
880
+ studioMii[0x1B] = hairCols3DS.indexOf(mii.hair.col);
881
+ if (!studioMii[0x1B]) studioMii[0x1B] = 8;
882
+ studioMii[0x1C] = mii.hair.flipped?1:0;
883
+ studioMii[7] = tables.eyes[mii.eyes.type[0]][mii.eyes.type[1]];
884
+ studioMii[4] = eyeCols3DS.indexOf(mii.eyes.col) + 8;
885
+ studioMii[6] = mii.eyes.size;
886
+ studioMii[3] = mii.eyes.squash;
887
+ studioMii[5] = mii.eyes.rot;
888
+ studioMii[8] = mii.eyes.distApart;
889
+ studioMii[9] = mii.eyes.yPos;
890
+ studioMii[0xE] = tables.eyebrows[mii.eyebrows.style[0]][mii.eyebrows.style[1]];
891
+ studioMii[0xB] = hairCols3DS.indexOf(mii.eyebrows.col);
892
+ if (!studioMii[0xB]) studioMii[0xB] = 8;
893
+ studioMii[0xD] = mii.eyebrows.size;
894
+ studioMii[0xA] = mii.eyebrows.squash;
895
+ studioMii[0xC] = mii.eyebrows.rot;
896
+ studioMii[0xF] = mii.eyebrows.distApart;
897
+ studioMii[0x10] = mii.eyebrows.yPos+3;
898
+ studioMii[0x2C] = tables.noses[mii.nose.type[0]][mii.nose.type[1]];
899
+ studioMii[0x2B] = mii.nose.size;
900
+ studioMii[0x2D] = mii.nose.yPos;
901
+ studioMii[0x26] = tables.mouths[mii.mouth.type[0]][mii.mouth.type[1]];
902
+ studioMii[0x24] = mouthCols3DS.indexOf(mii.mouth.col);
903
+ if (studioMii[0x24] < 4) {
904
+ studioMii[0x24] += 19;
905
+ } else {
906
+ studioMii[0x24] = 0;
907
+ }
908
+ studioMii[0x25] = mii.mouth.size;
909
+ studioMii[0x23] = mii.mouth.squash;
910
+ studioMii[0x27] = mii.mouth.yPos;
911
+ studioMii[0x29] = mii.facialHair.mustacheType;
912
+ studioMii[1] = mii.facialHair.beardType;
913
+ studioMii[0] = mii.facialHair.col;
914
+ if (!studioMii[0]) studioMii[0] = 8;
915
+ studioMii[0x28] = mii.facialHair.mustacheSize;
916
+ studioMii[0x2A] = mii.facialHair.mustacheYPos;
917
+ studioMii[0x19] = mii.glasses.type;
918
+ studioMii[0x17] = mii.glasses.col;
919
+ if (!studioMii[0x17]) {
920
+ studioMii[0x17] = 8;
921
+ } else if (studioMii[0x17] < 6) {
922
+ studioMii[0x17] += 13;
923
+ } else {
924
+ studioMii[0x17] = 0;
925
+ }
926
+ studioMii[0x18] = mii.glasses.size;
927
+ studioMii[0x1A] = mii.glasses.yPos;
928
+ studioMii[0x20] = mii.mole.on?1:0;
929
+ studioMii[0x1F] = mii.mole.size;
930
+ studioMii[0x21] = mii.mole.xPos;
931
+ studioMii[0x22] = mii.mole.yPos;
932
+ downloadImage('https://studio.mii.nintendo.com/miis/image.png?data=' + encodeStudio(studioMii) + "&width=270&type=face","./temp.png").then(d=>{
933
+ Jimp.read(mii.name+'Output.png', (err, fir_img) => {
934
+ if(err) {
935
+ console.log(err);
936
+ } else {
937
+ Jimp.read('temp.png', (err, sec_img) => {
938
+ if(err) {
939
+ console.log(err);
940
+ } else {
941
+ fir_img.resize(424, 424);
942
+ sec_img.resize(130,130);
943
+ const canvas = new Jimp(sec_img.bitmap.width, sec_img.bitmap.height, 0xFFFFFFFF);
944
+ canvas.composite(sec_img, 0, 0);
945
+ fir_img.blit(canvas, 212-130/2,212-130/2);
946
+ Jimp.loadFont(Jimp.FONT_SANS_16_BLACK).then(font => {
947
+ fir_img.print(font, 0, 50, {
948
+ text: mii.name,
949
+ alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
950
+ alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
951
+ }, 424, 424);
952
+ Jimp.read('./node_modules/miijs/crown.jpg',(err,thi_img)=>{
953
+ thi_img.resize(40,20);
954
+ if(mii.info.type==="Special") fir_img.blit(thi_img,232,150);
955
+ fir_img.write(outPath);
956
+ fs.unlinkSync("./temp.png");
957
+ });
958
+ });
959
+ }
960
+ })
961
+ }
962
+ fs.unlinkSync(mii.name+"Output.png");
963
+ });
964
+ });
965
+ }
966
+ }