Mostly nuking old system
This commit is contained in:
1 parent
b37e5f45ca
commit
e5e8c49f6c
97 files changed
+1454
-408
No files matched your search
+11
-11
@@ -82,7 +82,7 @@ endif()
|
|||||||
add_subdirectory(tools)
|
add_subdirectory(tools)
|
||||||
|
|
||||||
# Assets
|
# Assets
|
||||||
add_subdirectory(assets)
|
# add_subdirectory(assets)
|
||||||
|
|
||||||
# Add libraries
|
# Add libraries
|
||||||
if(DUSK_TARGET_SYSTEM STREQUAL "linux")
|
if(DUSK_TARGET_SYSTEM STREQUAL "linux")
|
||||||
@@ -176,16 +176,16 @@ if(ENABLE_TESTS)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Build assets
|
# Build assets
|
||||||
dusk_run_python(
|
# dusk_run_python(
|
||||||
DUSK_ASSETS_BUILT
|
# DUSK_ASSETS_BUILT
|
||||||
tools.asset.bundle
|
# tools.asset.bundle
|
||||||
--assets ${DUSK_ASSETS_DIR}
|
# --assets ${DUSK_ASSETS_DIR}
|
||||||
--output-assets ${DUSK_BUILT_ASSETS_DIR}
|
# --output-assets ${DUSK_BUILT_ASSETS_DIR}
|
||||||
--output-file ${DUSK_BUILD_DIR}/dusk.dsk
|
# --output-file ${DUSK_BUILD_DIR}/dusk.dsk
|
||||||
--headers-dir ${DUSK_GENERATED_HEADERS_DIR}
|
# --headers-dir ${DUSK_GENERATED_HEADERS_DIR}
|
||||||
--input ${DUSK_ASSETS}
|
# --input ${DUSK_ASSETS}
|
||||||
)
|
# )
|
||||||
add_dependencies(${DUSK_LIBRARY_TARGET_NAME} DUSK_ASSETS_BUILT)
|
# add_dependencies(${DUSK_LIBRARY_TARGET_NAME} DUSK_ASSETS_BUILT)
|
||||||
|
|
||||||
# Include generated headers
|
# Include generated headers
|
||||||
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
|
|||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,22 +0,0 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
|
||||||
#
|
|
||||||
# This software is released under the MIT License.
|
|
||||||
# https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
set(DUSK_GAME_ASSETS_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "Game assets directory")
|
|
||||||
|
|
||||||
# Palette asset needs to be added before any images.
|
|
||||||
add_subdirectory(palette)
|
|
||||||
|
|
||||||
# Languages need to be added before anything that uses text.
|
|
||||||
add_subdirectory(locale)
|
|
||||||
|
|
||||||
# Rest, order doesn't matter
|
|
||||||
add_asset(SCRIPT init.lua)
|
|
||||||
|
|
||||||
# Subdirs
|
|
||||||
# add_subdirectory(entity)
|
|
||||||
# add_subdirectory(map)
|
|
||||||
add_subdirectory(ui)
|
|
||||||
add_subdirectory(minesweeper)
|
|
||||||
add_subdirectory(scene)
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
|
||||||
#
|
|
||||||
# This software is released under the MIT License.
|
|
||||||
# https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
add_asset(TILESET entities.tsx)
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 336 B |
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<tileset version="1.10" tiledversion="1.11.2" name="entities" tilewidth="16" tileheight="16" tilecount="64" columns="8">
|
|
||||||
<image source="entities.png" width="128" height="128"/>
|
|
||||||
</tileset>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
|
||||||
#
|
|
||||||
# This software is released under the MIT License.
|
|
||||||
# https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
add_asset(LANGUAGE en_US.po)
|
|
||||||
@@ -7,9 +7,3 @@ msgstr ""
|
|||||||
|
|
||||||
msgid "ui.test"
|
msgid "ui.test"
|
||||||
msgstr "Hello this is a test."
|
msgstr "Hello this is a test."
|
||||||
|
|
||||||
msgid "map.test"
|
|
||||||
msgstr "This is a map test."
|
|
||||||
|
|
||||||
msgid "test.test2"
|
|
||||||
msgstr "This is another test."
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
|
||||||
#
|
|
||||||
# This software is released under the MIT License.
|
|
||||||
# https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
add_asset(PALETTE palette0.png)
|
|
||||||
add_asset(PALETTE paletteMinesweeper.png)
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 241 B |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 168 B |
@@ -1,7 +0,0 @@
|
|||||||
# Copyright (c) 2025 Dominic Masters
|
|
||||||
#
|
|
||||||
# This software is released under the MIT License.
|
|
||||||
# https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
add_asset(SCRIPT initial.lua)
|
|
||||||
add_asset(SCRIPT minesweeper.lua)
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
module('spritebatch')
|
|
||||||
module('camera')
|
|
||||||
module('color')
|
|
||||||
module('text')
|
|
||||||
module('screen')
|
|
||||||
module('time')
|
|
||||||
module('glm')
|
|
||||||
|
|
||||||
screenSetBackground(colorBlack())
|
|
||||||
camera = cameraCreate(CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC)
|
|
||||||
|
|
||||||
text = "Hello World"
|
|
||||||
|
|
||||||
function sceneDispose()
|
|
||||||
end
|
|
||||||
|
|
||||||
function sceneUpdate()
|
|
||||||
end
|
|
||||||
|
|
||||||
function sceneRender()
|
|
||||||
-- UI Test
|
|
||||||
cameraPushMatrix(camera)
|
|
||||||
camera.bottom = screenGetHeight()
|
|
||||||
camera.right = screenGetWidth()
|
|
||||||
|
|
||||||
width, height = textMeasure(text)
|
|
||||||
x = (screenGetWidth() - width)
|
|
||||||
x = math.sin(TIME.time * 2) * (x / 2) + (x / 2)
|
|
||||||
y = (screenGetHeight() - height) / 2
|
|
||||||
y = math.cos(TIME.time * 3) * (y) + (y)
|
|
||||||
|
|
||||||
-- For each letter
|
|
||||||
for i = 1, #text do
|
|
||||||
letter = text:sub(i, i)
|
|
||||||
letterWidth, _ = textMeasure(letter)
|
|
||||||
|
|
||||||
-- Draw letter with rainbow color
|
|
||||||
textDraw(x, y, letter, colorRainbow((i - 1) * 0.1, 8))
|
|
||||||
x = x + letterWidth
|
|
||||||
end
|
|
||||||
|
|
||||||
cameraPopMatrix()
|
|
||||||
end
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 758 B |
Binary file not shown.
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<tileset version="1.10" tiledversion="1.11.2" name="prarie" tilewidth="16" tileheight="16" tilecount="21" columns="7">
|
|
||||||
<image source="prarie.png" width="112" height="48"/>
|
|
||||||
</tileset>
|
|
||||||
+23
-51
@@ -232,6 +232,20 @@ errorret_t assetLoad(const char_t *filename, void *output) {
|
|||||||
assertStrLenMax(filename, FILENAME_MAX, "Filename too long.");
|
assertStrLenMax(filename, FILENAME_MAX, "Filename too long.");
|
||||||
assertNotNull(output, "Output pointer cannot be NULL.");
|
assertNotNull(output, "Output pointer cannot be NULL.");
|
||||||
|
|
||||||
|
// Determine the asset type by reading the extension
|
||||||
|
const assettypedef_t *def = NULL;
|
||||||
|
for(uint_fast8_t i = 0; i < ASSET_TYPE_COUNT; i++) {
|
||||||
|
const assettypedef_t *cmp = &ASSET_TYPE_DEFINITIONS[i];
|
||||||
|
assertNotNull(cmp, "Asset type definition cannot be NULL.");
|
||||||
|
assertNotNull(cmp->extension, "Asset type definition has NULL extension.");
|
||||||
|
if(!stringEndsWithCaseInsensitive(filename, cmp->extension)) continue;
|
||||||
|
def = cmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(def == NULL) {
|
||||||
|
errorThrow("Unknown asset type for file: %s", filename);
|
||||||
|
}
|
||||||
|
|
||||||
// Get file size of the asset.
|
// Get file size of the asset.
|
||||||
zip_stat_t st;
|
zip_stat_t st;
|
||||||
zip_stat_init(&st);
|
zip_stat_init(&st);
|
||||||
@@ -241,8 +255,8 @@ errorret_t assetLoad(const char_t *filename, void *output) {
|
|||||||
|
|
||||||
// Minimum file size.
|
// Minimum file size.
|
||||||
zip_int64_t fileSize = (zip_int64_t)st.size;
|
zip_int64_t fileSize = (zip_int64_t)st.size;
|
||||||
if(fileSize < sizeof(assetheader_t)) {
|
if(fileSize <= 0) {
|
||||||
errorThrow("Asset file too small to contain header: %s", filename);
|
errorThrow("Asset file is empty: %s", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to open the file
|
// Try to open the file
|
||||||
@@ -250,61 +264,19 @@ errorret_t assetLoad(const char_t *filename, void *output) {
|
|||||||
if(file == NULL) {
|
if(file == NULL) {
|
||||||
errorThrow("Failed to open asset file: %s", filename);
|
errorThrow("Failed to open asset file: %s", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the header.
|
|
||||||
zip_int64_t bytesRemaining = fileSize;
|
|
||||||
assetheader_t header;
|
|
||||||
memoryZero(&header, sizeof(assetheader_t));
|
|
||||||
zip_int64_t bytesRead = zip_fread(
|
|
||||||
file,
|
|
||||||
&header,
|
|
||||||
(zip_uint64_t)sizeof(assetheader_t)
|
|
||||||
);
|
|
||||||
if((size_t)bytesRead != sizeof(assetheader_t)) {
|
|
||||||
zip_fclose(file);
|
|
||||||
errorThrow("Failed to read asset header for: %s", filename);
|
|
||||||
}
|
|
||||||
bytesRemaining -= (zip_uint64_t)bytesRead;
|
|
||||||
|
|
||||||
assertTrue(sizeof(assetheader_t) == ASSET_HEADER_SIZE, "Asset header size mismatch.");
|
// Load the asset data
|
||||||
assertTrue(bytesRead == ASSET_HEADER_SIZE, "Asset header read size mismatch.");
|
|
||||||
|
|
||||||
// Find the asset type based on the header
|
|
||||||
const assettypedef_t *def = NULL;
|
|
||||||
for(uint_fast8_t i = 0; i < ASSET_TYPE_COUNT; i++) {
|
|
||||||
const assettypedef_t *cmp = &ASSET_TYPE_DEFINITIONS[i];
|
|
||||||
if(cmp->header == NULL) continue;
|
|
||||||
|
|
||||||
// strcmp didn't work because it's a fixed char_t[3] I think, or maybe
|
|
||||||
// because of the packed struct?
|
|
||||||
bool_t match = true;
|
|
||||||
for(size_t h = 0; h < ASSET_HEADER_SIZE; h++) {
|
|
||||||
if(header.header[h] == cmp->header[h]) continue;
|
|
||||||
match = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!match) continue;
|
|
||||||
|
|
||||||
def = cmp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(def == NULL) {
|
|
||||||
zip_fclose(file);
|
|
||||||
errorThrow("Unknown asset type for file: %s", filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We found the asset type, now load the asset data
|
|
||||||
switch(def->loadStrategy) {
|
switch(def->loadStrategy) {
|
||||||
case ASSET_LOAD_STRAT_ENTIRE:
|
case ASSET_LOAD_STRAT_ENTIRE:
|
||||||
assertNotNull(def->entire, "Asset load function cannot be NULL.");
|
assertNotNull(def->entire, "Asset load function cannot be NULL.");
|
||||||
|
|
||||||
// Must have more to read
|
// Must have more to read
|
||||||
if(bytesRemaining <= 0) {
|
if(fileSize <= 0) {
|
||||||
zip_fclose(file);
|
zip_fclose(file);
|
||||||
errorThrow("No data remaining to read for asset: %s", filename);
|
errorThrow("No data remaining to read for asset: %s", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bytesRemaining > def->dataSize) {
|
if(fileSize > def->dataSize) {
|
||||||
zip_fclose(file);
|
zip_fclose(file);
|
||||||
errorThrow(
|
errorThrow(
|
||||||
"Asset file has too much data remaining after header: %s",
|
"Asset file has too much data remaining after header: %s",
|
||||||
@@ -313,20 +285,20 @@ errorret_t assetLoad(const char_t *filename, void *output) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create space to read the entire asset data
|
// Create space to read the entire asset data
|
||||||
void *data = memoryAllocate(bytesRemaining);
|
void *data = memoryAllocate(fileSize);
|
||||||
if(!data) {
|
if(!data) {
|
||||||
zip_fclose(file);
|
zip_fclose(file);
|
||||||
errorThrow("Failed to allocate memory for asset data of file: %s", filename);
|
errorThrow("Failed to allocate memory for asset data of file: %s", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read in the asset data.
|
// Read in the asset data.
|
||||||
bytesRead = zip_fread(file, data, bytesRemaining);
|
zip_int64_t bytesRead = zip_fread(file, data, fileSize);
|
||||||
if(bytesRead == 0 || bytesRead > bytesRemaining) {
|
if(bytesRead == 0 || bytesRead > fileSize) {
|
||||||
memoryFree(data);
|
memoryFree(data);
|
||||||
zip_fclose(file);
|
zip_fclose(file);
|
||||||
errorThrow("Failed to read asset data for file: %s", filename);
|
errorThrow("Failed to read asset data for file: %s", filename);
|
||||||
}
|
}
|
||||||
bytesRemaining -= bytesRead;
|
fileSize -= bytesRead;
|
||||||
|
|
||||||
// Close the file now we have the data
|
// Close the file now we have the data
|
||||||
zip_fclose(file);
|
zip_fclose(file);
|
||||||
|
|||||||
@@ -72,12 +72,6 @@ static const char_t *ASSET_SEARCH_PATHS[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct {
|
|
||||||
char_t header[ASSET_HEADER_SIZE];
|
|
||||||
} assetheader_t;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
zip_t *zip;
|
zip_t *zip;
|
||||||
char_t systemPath[FILENAME_MAX];
|
char_t systemPath[FILENAME_MAX];
|
||||||
|
|||||||
+19
-28
@@ -6,8 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "type/assetpaletteimage.h"
|
#include "type/assettexture.h"
|
||||||
#include "type/assetalphaimage.h"
|
|
||||||
#include "type/assetlanguage.h"
|
#include "type/assetlanguage.h"
|
||||||
#include "type/assetscript.h"
|
#include "type/assetscript.h"
|
||||||
#include "type/assetmap.h"
|
#include "type/assetmap.h"
|
||||||
@@ -17,8 +16,7 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
ASSET_TYPE_NULL,
|
ASSET_TYPE_NULL,
|
||||||
|
|
||||||
ASSET_TYPE_PALETTE_IMAGE,
|
ASSET_TYPE_TEXTURE,
|
||||||
ASSET_TYPE_ALPHA_IMAGE,
|
|
||||||
ASSET_TYPE_LANGUAGE,
|
ASSET_TYPE_LANGUAGE,
|
||||||
ASSET_TYPE_SCRIPT,
|
ASSET_TYPE_SCRIPT,
|
||||||
ASSET_TYPE_MAP,
|
ASSET_TYPE_MAP,
|
||||||
@@ -38,7 +36,7 @@ typedef struct assetcustom_s {
|
|||||||
} assetcustom_t;
|
} assetcustom_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char_t *header;
|
const char_t *extension;
|
||||||
const size_t dataSize;
|
const size_t dataSize;
|
||||||
const assetloadstrat_t loadStrategy;
|
const assetloadstrat_t loadStrategy;
|
||||||
union {
|
union {
|
||||||
@@ -52,41 +50,34 @@ static const assettypedef_t ASSET_TYPE_DEFINITIONS[ASSET_TYPE_COUNT] = {
|
|||||||
0
|
0
|
||||||
},
|
},
|
||||||
|
|
||||||
[ASSET_TYPE_PALETTE_IMAGE] = {
|
[ASSET_TYPE_TEXTURE] = {
|
||||||
.header = "DPI",
|
.extension = "dpt",
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
||||||
.dataSize = sizeof(assetpaletteimage_t),
|
.dataSize = sizeof(assettexture_t),
|
||||||
.entire = assetPaletteImageLoad
|
.entire = assetTextureLoad
|
||||||
},
|
|
||||||
|
|
||||||
[ASSET_TYPE_ALPHA_IMAGE] = {
|
|
||||||
.header = "DAI",
|
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
|
||||||
.dataSize = sizeof(assetalphaimage_t),
|
|
||||||
.entire = assetAlphaImageLoad
|
|
||||||
},
|
},
|
||||||
|
|
||||||
[ASSET_TYPE_LANGUAGE] = {
|
[ASSET_TYPE_LANGUAGE] = {
|
||||||
.header = "DLF",
|
.extension = "DLF",
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||||
.custom = assetLanguageHandler
|
.custom = assetLanguageHandler
|
||||||
},
|
},
|
||||||
|
|
||||||
[ASSET_TYPE_SCRIPT] = {
|
[ASSET_TYPE_SCRIPT] = {
|
||||||
.header = "DSF",
|
.extension = "lua",
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||||
.custom = assetScriptHandler
|
.custom = assetScriptHandler
|
||||||
},
|
},
|
||||||
|
|
||||||
[ASSET_TYPE_MAP] = {
|
// [ASSET_TYPE_MAP] = {
|
||||||
.header = "DMF",
|
// .extension = "DMF",
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
// .loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||||
.custom = assetMapHandler
|
// .custom = assetMapHandler
|
||||||
},
|
// },
|
||||||
|
|
||||||
[ASSET_TYPE_MAP_CHUNK] = {
|
// [ASSET_TYPE_MAP_CHUNK] = {
|
||||||
.header = "DMC",
|
// .extension = "DMC",
|
||||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
// .loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||||
.custom = assetMapChunkHandler
|
// .custom = assetMapChunkHandler
|
||||||
},
|
// },
|
||||||
};
|
};
|
||||||
@@ -6,8 +6,7 @@
|
|||||||
# Sources
|
# Sources
|
||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
assetalphaimage.c
|
assettexture.c
|
||||||
assetpaletteimage.c
|
|
||||||
assetlanguage.c
|
assetlanguage.c
|
||||||
assetscript.c
|
assetscript.c
|
||||||
assetmap.c
|
assetmap.c
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "assetalphaimage.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "display/texture.h"
|
|
||||||
|
|
||||||
#include "debug/debug.h"
|
|
||||||
|
|
||||||
errorret_t assetAlphaImageLoad(void *data, void *output) {
|
|
||||||
assertNotNull(data, "Data pointer cannot be NULL.");
|
|
||||||
assertNotNull(output, "Output pointer cannot be NULL.");
|
|
||||||
|
|
||||||
assetalphaimage_t *dataPtr = (assetalphaimage_t *)data;
|
|
||||||
texture_t *outputPtr = (texture_t *)output;
|
|
||||||
|
|
||||||
// Fix endian
|
|
||||||
dataPtr->width = le32toh(dataPtr->width);
|
|
||||||
dataPtr->height = le32toh(dataPtr->height);
|
|
||||||
|
|
||||||
textureInit(
|
|
||||||
outputPtr,
|
|
||||||
dataPtr->width,
|
|
||||||
dataPtr->height,
|
|
||||||
TEXTURE_FORMAT_ALPHA,
|
|
||||||
(texturedata_t){ .alpha = { .data = dataPtr->pixels } }
|
|
||||||
);
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "error/error.h"
|
|
||||||
|
|
||||||
#define ASSET_ALPHA_IMAGE_WIDTH_MAX 256
|
|
||||||
#define ASSET_ALPHA_IMAGE_HEIGHT_MAX 256
|
|
||||||
#define ASSET_ALPHA_IMAGE_SIZE_MAX ( \
|
|
||||||
ASSET_ALPHA_IMAGE_WIDTH_MAX * ASSET_ALPHA_IMAGE_HEIGHT_MAX \
|
|
||||||
)
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct {
|
|
||||||
uint32_t width;
|
|
||||||
uint32_t height;
|
|
||||||
uint8_t pixels[ASSET_ALPHA_IMAGE_SIZE_MAX];
|
|
||||||
} assetalphaimage_t;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads an alpha image asset from the given asset structure. The asset must
|
|
||||||
* be of type ASSET_TYPE_ALPHA_IMAGE and must be loaded.
|
|
||||||
*
|
|
||||||
* @param asset The asset to load the alpha image from.
|
|
||||||
* @return An error code.
|
|
||||||
*/
|
|
||||||
errorret_t assetAlphaImageLoad(void *data, void *output);
|
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "locale/language/keys.h"
|
|
||||||
#include "error/error.h"
|
#include "error/error.h"
|
||||||
#include "duskdefs.h"
|
#include "duskdefs.h"
|
||||||
#include <zip.h>
|
#include <zip.h>
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "error/error.h"
|
|
||||||
|
|
||||||
#define ASSET_PALETTE_IMAGE_WIDTH_MAX 256
|
|
||||||
#define ASSET_PALETTE_IMAGE_HEIGHT_MAX 256
|
|
||||||
#define ASSET_PALETTE_IMAGE_SIZE_MAX ( \
|
|
||||||
ASSET_PALETTE_IMAGE_WIDTH_MAX * ASSET_PALETTE_IMAGE_HEIGHT_MAX \
|
|
||||||
)
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
typedef struct {
|
|
||||||
uint32_t width;
|
|
||||||
uint32_t height;
|
|
||||||
uint8_t paletteIndex;
|
|
||||||
uint8_t palette[ASSET_PALETTE_IMAGE_SIZE_MAX];
|
|
||||||
} assetpaletteimage_t;
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a palette image asset from the given data pointer into the output
|
|
||||||
* texture.
|
|
||||||
*
|
|
||||||
* @param data Pointer to the raw assetpaletteimage_t data.
|
|
||||||
* @param output Pointer to the texture_t to load the image into.
|
|
||||||
* @return An error code.
|
|
||||||
*/
|
|
||||||
errorret_t assetPaletteImageLoad(void *data, void *output);
|
|
||||||
@@ -5,37 +5,38 @@
|
|||||||
* https://opensource.org/licenses/MIT
|
* https://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "assetpaletteimage.h"
|
#include "assettexture.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "display/texture.h"
|
#include "display/texture.h"
|
||||||
#include "display/palette/palettelist.h"
|
|
||||||
|
|
||||||
errorret_t assetPaletteImageLoad(void *data, void *output) {
|
errorret_t assetPaletteImageLoad(void *data, void *output) {
|
||||||
assertNotNull(data, "Data pointer cannot be NULL.");
|
assertNotNull(data, "Data pointer cannot be NULL.");
|
||||||
assertNotNull(output, "Output pointer cannot be NULL.");
|
assertNotNull(output, "Output pointer cannot be NULL.");
|
||||||
|
|
||||||
assetpaletteimage_t *assetData = (assetpaletteimage_t *)data;
|
assettexture_t *assetData = (assettexture_t *)data;
|
||||||
texture_t *texture = (texture_t *)output;
|
texture_t *texture = (texture_t *)output;
|
||||||
|
|
||||||
// Fix endian
|
// Fix endian
|
||||||
assetData->width = le32toh(assetData->width);
|
assetData->width = le32toh(assetData->width);
|
||||||
assetData->height = le32toh(assetData->height);
|
assetData->height = le32toh(assetData->height);
|
||||||
|
|
||||||
const palette_t *pal = PALETTE_LIST[assetData->paletteIndex];
|
|
||||||
assertNotNull(pal, "Palette index is out of bounds");
|
|
||||||
|
|
||||||
textureInit(
|
errorThrow("Hello World\n");
|
||||||
texture,
|
|
||||||
assetData->width,
|
|
||||||
assetData->height,
|
|
||||||
TEXTURE_FORMAT_PALETTE,
|
|
||||||
(texturedata_t){
|
|
||||||
.palette = {
|
|
||||||
.palette = pal,
|
|
||||||
.data = assetData->palette
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
errorOk();
|
// const palette_t *pal = PALETTE_LIST[assetData->paletteIndex];
|
||||||
|
// assertNotNull(pal, "Palette index is out of bounds");
|
||||||
|
|
||||||
|
// textureInit(
|
||||||
|
// texture,
|
||||||
|
// assetData->width,
|
||||||
|
// assetData->height,
|
||||||
|
// TEXTURE_FORMAT_PALETTE,
|
||||||
|
// (texturedata_t){
|
||||||
|
// .palette = {
|
||||||
|
// .palette = pal,
|
||||||
|
// .data = assetData->palette
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
|
// errorOk();
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "error/error.h"
|
||||||
|
|
||||||
|
#define ASSET_TEXTURE_WIDTH_MAX 256
|
||||||
|
#define ASSET_TEXTURE_HEIGHT_MAX 256
|
||||||
|
#define ASSET_TEXTURE_SIZE_MAX ( \
|
||||||
|
ASSET_TEXTURE_WIDTH_MAX * ASSET_TEXTURE_HEIGHT_MAX \
|
||||||
|
)
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
typedef struct {
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
uint8_t paletteIndex;
|
||||||
|
uint8_t palette[ASSET_TEXTURE_SIZE_MAX];
|
||||||
|
} assettexture_t;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a palettized texture from the given data pointer into the output
|
||||||
|
* texture.
|
||||||
|
*
|
||||||
|
* @param data Pointer to the raw assettexture_t data.
|
||||||
|
* @param output Pointer to the texture_t to load the image into.
|
||||||
|
* @return An error code.
|
||||||
|
*/
|
||||||
|
errorret_t assetTextureLoad(void *data, void *output);
|
||||||
@@ -6,4 +6,5 @@
|
|||||||
# Sources
|
# Sources
|
||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
|
palette.c
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "palette.h"
|
||||||
@@ -8,7 +8,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "display/color.h"
|
#include "display/color.h"
|
||||||
|
|
||||||
|
#define PALETTE_COUNT 4
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const uint8_t colorCount;
|
const uint8_t colorCount;
|
||||||
const color_t *colors;
|
const color_t *colors;
|
||||||
} palette_t;
|
} palette_t;
|
||||||
|
|
||||||
|
extern palette_t PALETTES[PALETTE_COUNT];
|
||||||
+3
-2
@@ -12,14 +12,15 @@
|
|||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
|
|
||||||
texture_t DEFAULT_FONT_TEXTURE;
|
texture_t DEFAULT_FONT_TEXTURE;
|
||||||
|
tileset_t DEFAULT_FONT_TILESET;
|
||||||
|
|
||||||
errorret_t textInit(void) {
|
errorret_t textInit(void) {
|
||||||
errorChain(assetLoad(DEFAULT_FONT_TILESET.image, &DEFAULT_FONT_TEXTURE));
|
// errorChain(assetLoad(DEFAULT_FONT_TILESET.image, &DEFAULT_FONT_TEXTURE));
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
void textDispose(void) {
|
void textDispose(void) {
|
||||||
textureDispose(&DEFAULT_FONT_TEXTURE);
|
// textureDispose(&DEFAULT_FONT_TEXTURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void textDrawChar(
|
void textDrawChar(
|
||||||
|
|||||||
+2
-3
@@ -9,12 +9,11 @@
|
|||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
#include "display/texture.h"
|
#include "display/texture.h"
|
||||||
#include "display/tileset/tileset.h"
|
#include "display/tileset/tileset.h"
|
||||||
#include "display/tileset/tileset_minogram.h"
|
|
||||||
|
|
||||||
#define TEXT_CHAR_START '!'
|
#define TEXT_CHAR_START '!'
|
||||||
|
|
||||||
extern texture_t DEFAULT_FONT_TEXTURE;
|
// extern texture_t DEFAULT_FONT_TEXTURE;
|
||||||
#define DEFAULT_FONT_TILESET TILESET_MINOGRAM
|
// #define DEFAULT_FONT_TILESET TILESET_MINOGRAM
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the text system.
|
* Initializes the text system.
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "util/math.h"
|
#include "util/math.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
#include "display/palette/palettelist.h"
|
|
||||||
#include "debug/debug.h"
|
#include "debug/debug.h"
|
||||||
|
|
||||||
const texture_t *TEXTURE_BOUND = NULL;
|
const texture_t *TEXTURE_BOUND = NULL;
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tileset.h"
|
#include "tileset.h"
|
||||||
#include "display/tileset/tilesetlist.h"
|
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
|
||||||
@@ -34,13 +33,4 @@ void tilesetPositionGetUV(
|
|||||||
outUV[1] = ((float_t)row) * tileset->uv[1];
|
outUV[1] = ((float_t)row) * tileset->uv[1];
|
||||||
outUV[2] = outUV[0] + tileset->uv[0];
|
outUV[2] = outUV[0] + tileset->uv[0];
|
||||||
outUV[3] = outUV[1] + tileset->uv[1];
|
outUV[3] = outUV[1] + tileset->uv[1];
|
||||||
}
|
|
||||||
|
|
||||||
const tileset_t * tilesetGetByName(const char_t *name) {
|
|
||||||
assertStrLenMin(name, 1, "Tileset name cannot be empty");
|
|
||||||
for(uint32_t i = 0; i < TILESET_LIST_COUNT; i++) {
|
|
||||||
if(stringCompare(TILESET_LIST[i]->name, name) != 0) continue;
|
|
||||||
return TILESET_LIST[i];
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
@@ -45,12 +45,4 @@ void tilesetPositionGetUV(
|
|||||||
const uint16_t column,
|
const uint16_t column,
|
||||||
const uint16_t row,
|
const uint16_t row,
|
||||||
vec4 outUV
|
vec4 outUV
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a tileset by its name.
|
|
||||||
*
|
|
||||||
* @param name The name of the tileset to get.
|
|
||||||
* @return The tileset with the given name, or NULL if not found.
|
|
||||||
*/
|
|
||||||
const tileset_t* tilesetGetByName(const char_t *name);
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *nothing;
|
||||||
|
} dusklocale_t;
|
||||||
+1
-11
@@ -4,14 +4,4 @@
|
|||||||
# https://opensource.org/licenses/MIT
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
add_subdirectory(run_python)
|
add_subdirectory(run_python)
|
||||||
add_subdirectory(env_to_h)
|
add_subdirectory(env_to_h)
|
||||||
|
|
||||||
# Function that adds an asset to be compiled
|
|
||||||
function(add_asset ASSET_TYPE ASSET_PATH)
|
|
||||||
set(FULL_ASSET_PATH "${CMAKE_CURRENT_LIST_DIR}/${ASSET_PATH}")
|
|
||||||
string(JOIN "%" ASSETS_ARGS ${ARGN})
|
|
||||||
list(APPEND DUSK_ASSETS
|
|
||||||
"${ASSET_TYPE}#${FULL_ASSET_PATH}#${ASSETS_ARGS}"
|
|
||||||
)
|
|
||||||
set(DUSK_ASSETS ${DUSK_ASSETS} CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
|
||||||
endfunction()
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import csv
|
import csv
|
||||||
from tools.util.type import detectType, stringToCType, typeToCType
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description="Color CSV to .h defines")
|
parser = argparse.ArgumentParser(description="Color CSV to .h defines")
|
||||||
parser.add_argument("--csv", required=True, help="Path to color CSV file")
|
parser.add_argument("--csv", required=True, help="Path to color CSV file")
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import csv
|
import csv
|
||||||
from tools.util.type import detectType, stringToCType, typeToCType
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description="Input CSV to .h defines")
|
parser = argparse.ArgumentParser(description="Input CSV to .h defines")
|
||||||
parser.add_argument("--csv", required=True, help="Path to Input CSV file")
|
parser.add_argument("--csv", required=True, help="Path to Input CSV file")
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import csv
|
import csv
|
||||||
from tools.util.type import detectType, stringToCType, typeToCType
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description="Item CSV to .h defines")
|
parser = argparse.ArgumentParser(description="Item CSV to .h defines")
|
||||||
parser.add_argument("--csv", required=True, help="Path to item CSV file")
|
parser.add_argument("--csv", required=True, help="Path to item CSV file")
|
||||||
|
|||||||
@@ -0,0 +1,698 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Dusk Tools / Palette Indexer</title>
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
image-rendering: pixelated;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Dusk Palette Indexer</h1>
|
||||||
|
<p>
|
||||||
|
This tool takes an input image and creates a palettized version of it.
|
||||||
|
You will get two files, a .dpf (Dusk Palette File) and a .dpt
|
||||||
|
(Dusk Palettized Texture). The first being the palette, which I recommend
|
||||||
|
reusing across multiple images, and the second being the indexed image,
|
||||||
|
which uses the colors from the palette.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Also, dusk previously supported Alpha textures, but due to so many little
|
||||||
|
platform differences I realized it is simpler and about as much work to
|
||||||
|
get palettized textures working instead. As a result I suggest creating a
|
||||||
|
single palette for your alpha textures, and reusing that globally.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>Input Image</h2>
|
||||||
|
<div>
|
||||||
|
<input type="file" data-file-input />
|
||||||
|
</div>
|
||||||
|
<p data-file-error style="color:red;display:none;"></p>
|
||||||
|
<canvas data-input-preview style="border:1px solid black;"></canvas>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>Palette</h2>
|
||||||
|
<div>
|
||||||
|
<button data-palette-add>Add Color</button>
|
||||||
|
<button data-palette-append>Append Palette</button>
|
||||||
|
<button data-palette-clear>Clear Palette</button>
|
||||||
|
<button data-palette-optimize>Optimize Palette</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-palette-entries style="display:grid;grid-template-columns:repeat(auto-fill, minmax(400px, 1fr));gap:16px;margin-top:16px;"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
Preview Background:
|
||||||
|
<button data-page-bg-white>White</button>
|
||||||
|
<button data-page-bg-transparent>Black</button>
|
||||||
|
<button data-page-bg-checkerboard>Checkerboard</button>
|
||||||
|
<button data-page-bg-magenta>Magenta</button>
|
||||||
|
<button data-page-bg-blue>Blue</button>
|
||||||
|
<button data-page-bg-green>Green</button>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>Palette Preview</h2>
|
||||||
|
|
||||||
|
<h3>Palette</h3>
|
||||||
|
<div>
|
||||||
|
<button data-palette-download>Download Palette</button>
|
||||||
|
</div>
|
||||||
|
<canvas data-palette-preview style="border:1px solid black;"></canvas>
|
||||||
|
<p data-palette-information></p>
|
||||||
|
|
||||||
|
<h3>Indexed Image</h3>
|
||||||
|
<div>
|
||||||
|
<button data-indexed-download>Download Indexed Image</button>
|
||||||
|
</div>
|
||||||
|
<div data-output-error style="color:red;display:none;"></div>
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
Preview Scale:
|
||||||
|
<input type="number" value="2" data-indexed-preview-scale min="1" step="1" />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<canvas data-output-preview style="border:1px solid black;"></canvas>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
const elError = document.querySelector('[data-file-error]');
|
||||||
|
const elFile = document.querySelector('[data-file-input]');
|
||||||
|
const elInputPreview = document.querySelector('[data-input-preview]');
|
||||||
|
const elPalettePreview = document.querySelector('[data-palette-preview]');
|
||||||
|
const elOutputPreview = document.querySelector('[data-output-preview]');
|
||||||
|
const elPaletteInformation = document.querySelector('[data-palette-information]');
|
||||||
|
const elSourceFromInput = document.querySelector('[data-source-from-input]');
|
||||||
|
const elPaletteAdd = document.querySelector('[data-palette-add]');
|
||||||
|
const elPaletteEntries = document.querySelector('[data-palette-entries]');
|
||||||
|
const elPreviewScale = document.querySelector('[data-indexed-preview-scale]');
|
||||||
|
const elClearPalette = document.querySelector('[data-palette-clear]');
|
||||||
|
const elAppendPalette = document.querySelector('[data-palette-append]');
|
||||||
|
const elOutputError = document.querySelector('[data-output-error]');
|
||||||
|
const elOptimizePalette = document.querySelector('[data-palette-optimize]');
|
||||||
|
const btnBackgroundWhite = document.querySelector('[data-page-bg-white]');
|
||||||
|
const btnBackgroundTransparent = document.querySelector('[data-page-bg-transparent]');
|
||||||
|
const btnBackgroundCheckerboard = document.querySelector('[data-page-bg-checkerboard]');
|
||||||
|
const btnBackgroundMagenta = document.querySelector('[data-page-bg-magenta]');
|
||||||
|
const btnBackgroundBlue = document.querySelector('[data-page-bg-blue]');
|
||||||
|
const btnBackgroundGreen = document.querySelector('[data-page-bg-green]');
|
||||||
|
const btnDownloadPalette = document.querySelector('[data-palette-download]');
|
||||||
|
const btnDownloadImage = document.querySelector('[data-indexed-download]');
|
||||||
|
|
||||||
|
let imageWidth = 0;
|
||||||
|
let imageHeight = 0;
|
||||||
|
let palette = [];// Array of [ r, g, b, a ]
|
||||||
|
let indexedImage = [ ];// Array of indexes
|
||||||
|
|
||||||
|
const nextPowerOfTwo = (x) => {
|
||||||
|
return Math.pow(2, Math.ceil(Math.log2(x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
const sourcePaletteFromImage = (image) => {
|
||||||
|
// Get unique colors
|
||||||
|
const elCanvas = document.createElement('canvas');
|
||||||
|
elCanvas.width = image.width;
|
||||||
|
elCanvas.height = image.height;
|
||||||
|
const ctx = elCanvas.getContext('2d');
|
||||||
|
ctx.drawImage(image, 0, 0);
|
||||||
|
const imageData = ctx.getImageData(0, 0, image.width, image.height);
|
||||||
|
const data = imageData.data;
|
||||||
|
|
||||||
|
const palette = [];
|
||||||
|
for(let i = 0; i < data.length; i += 4) {
|
||||||
|
const color = [ data[i], data[i + 1], data[i + 2], data[i + 3] ];
|
||||||
|
if(!palette.some(c => c[0] === color[0] && c[1] === color[1] && c[2] === color[2] && c[3] === color[3])) {
|
||||||
|
palette.push(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateOutput = () => {
|
||||||
|
elOutputError.style.display = 'none';
|
||||||
|
|
||||||
|
// Update palette preview
|
||||||
|
const paletteScale = 8;
|
||||||
|
const uniquePalette = palette.filter((color, index) => {
|
||||||
|
if(color[3] === 0) {
|
||||||
|
// Find any other fully transparent pixel.
|
||||||
|
return index === palette.findIndex(c => c[3] === 0);
|
||||||
|
}
|
||||||
|
return index === palette.findIndex(c => c[0] === color[0] && c[1] === color[1] && c[2] === color[2] && c[3] === color[3]);
|
||||||
|
});
|
||||||
|
elPalettePreview.width = uniquePalette.length * paletteScale;
|
||||||
|
elPalettePreview.height = paletteScale;
|
||||||
|
const paletteCtx = elPalettePreview.getContext('2d');
|
||||||
|
uniquePalette.forEach((color, index) => {
|
||||||
|
paletteCtx.fillStyle = `rgba(${color[0]}, ${color[1]}, ${color[2]}, ${color[3] / 255})`;
|
||||||
|
paletteCtx.fillRect(index * paletteScale, 0, paletteScale, paletteScale);
|
||||||
|
});
|
||||||
|
elPaletteInformation.textContent = `Palette contains ${uniquePalette.length} colors (${palette.length - uniquePalette.length} duplicates).`;
|
||||||
|
|
||||||
|
// Update palette entries
|
||||||
|
elPaletteEntries.innerHTML = '';
|
||||||
|
palette.forEach((color, index) => {
|
||||||
|
const entry = document.createElement('div');
|
||||||
|
|
||||||
|
const epar = document.createElement('span');
|
||||||
|
epar.textContent = `Index ${index}`;
|
||||||
|
|
||||||
|
const ecolor = document.createElement('span');
|
||||||
|
ecolor.style.display = 'inline-block';
|
||||||
|
ecolor.style.width = '16px';
|
||||||
|
ecolor.style.height = '16px';
|
||||||
|
ecolor.style.marginLeft = '8px';
|
||||||
|
ecolor.style.backgroundColor = `rgba(${color[0]}, ${color[1]}, ${color[2]}, ${color[3] / 255})`;
|
||||||
|
ecolor.style.border = '1px solid black';
|
||||||
|
|
||||||
|
const header = document.createElement('div');
|
||||||
|
header.appendChild(epar);
|
||||||
|
header.appendChild(ecolor);
|
||||||
|
|
||||||
|
const inputR = document.createElement('input');
|
||||||
|
inputR.type = 'number';
|
||||||
|
inputR.value = color[0];
|
||||||
|
inputR.min = 0;
|
||||||
|
inputR.max = 255;
|
||||||
|
inputR.setAttribute('data-palette-index', index);
|
||||||
|
inputR.setAttribute('data-palette-channel', '0');
|
||||||
|
inputR.addEventListener('change', (event) => {
|
||||||
|
const idx = parseInt(event.target.getAttribute('data-palette-index'));
|
||||||
|
const channel = parseInt(event.target.getAttribute('data-palette-channel'));
|
||||||
|
const value = parseInt(event.target.value);
|
||||||
|
if(isNaN(value) || value < 0 || value > 255) {
|
||||||
|
event.target.value = palette[idx][channel];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
palette[idx][channel] = value;
|
||||||
|
updateOutput();
|
||||||
|
});
|
||||||
|
|
||||||
|
const inputG = document.createElement('input');
|
||||||
|
inputG.type = 'number';
|
||||||
|
inputG.value = color[1];
|
||||||
|
inputG.min = 0;
|
||||||
|
inputG.max = 255;
|
||||||
|
inputG.setAttribute('data-palette-index', index);
|
||||||
|
inputG.setAttribute('data-palette-channel', '1');
|
||||||
|
inputG.addEventListener('change', (event) => {
|
||||||
|
const idx = parseInt(event.target.getAttribute('data-palette-index'));
|
||||||
|
const channel = parseInt(event.target.getAttribute('data-palette-channel'));
|
||||||
|
const value = parseInt(event.target.value);
|
||||||
|
if(isNaN(value) || value < 0 || value > 255) {
|
||||||
|
event.target.value = palette[idx][channel];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
palette[idx][channel] = value;
|
||||||
|
updateOutput();
|
||||||
|
});
|
||||||
|
|
||||||
|
const inputB = document.createElement('input');
|
||||||
|
inputB.type = 'number';
|
||||||
|
inputB.value = color[2];
|
||||||
|
inputB.min = 0;
|
||||||
|
inputB.max = 255;
|
||||||
|
inputB.setAttribute('data-palette-index', index);
|
||||||
|
inputB.setAttribute('data-palette-channel', '2');
|
||||||
|
inputB.addEventListener('change', (event) => {
|
||||||
|
const idx = parseInt(event.target.getAttribute('data-palette-index'));
|
||||||
|
const channel = parseInt(event.target.getAttribute('data-palette-channel'));
|
||||||
|
const value = parseInt(event.target.value);
|
||||||
|
if(isNaN(value) || value < 0 || value > 255) {
|
||||||
|
event.target.value = palette[idx][channel];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
palette[idx][channel] = value;
|
||||||
|
updateOutput();
|
||||||
|
});
|
||||||
|
|
||||||
|
const inputA = document.createElement('input');
|
||||||
|
inputA.type = 'number';
|
||||||
|
inputA.value = color[3];
|
||||||
|
inputA.min = 0;
|
||||||
|
inputA.max = 255;
|
||||||
|
inputA.setAttribute('data-palette-index', index);
|
||||||
|
inputA.setAttribute('data-palette-channel', '3');
|
||||||
|
inputA.addEventListener('change', (event) => {
|
||||||
|
const idx = parseInt(event.target.getAttribute('data-palette-index'));
|
||||||
|
const channel = parseInt(event.target.getAttribute('data-palette-channel'));
|
||||||
|
const value = parseInt(event.target.value);
|
||||||
|
if(isNaN(value) || value < 0 || value > 255) {
|
||||||
|
event.target.value = palette[idx][channel];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
palette[idx][channel] = value;
|
||||||
|
updateOutput();
|
||||||
|
});
|
||||||
|
|
||||||
|
const colorArea = document.createElement('div');
|
||||||
|
colorArea.style.display = 'inline-block';
|
||||||
|
colorArea.appendChild(inputR);
|
||||||
|
colorArea.appendChild(inputG);
|
||||||
|
colorArea.appendChild(inputB);
|
||||||
|
colorArea.appendChild(inputA);
|
||||||
|
|
||||||
|
const buttonArea = document.createElement('div');
|
||||||
|
buttonArea.style.display = 'inline-block';
|
||||||
|
const btnRemove = document.createElement('button');
|
||||||
|
btnRemove.textContent = '-';
|
||||||
|
btnRemove.setAttribute('data-palette-index', index);
|
||||||
|
btnRemove.addEventListener('click', () => {
|
||||||
|
palette.splice(index, 1);
|
||||||
|
updateOutput();
|
||||||
|
});
|
||||||
|
buttonArea.appendChild(btnRemove);
|
||||||
|
|
||||||
|
const btnUp = document.createElement('button');
|
||||||
|
btnUp.textContent = '↑';
|
||||||
|
btnUp.setAttribute('data-palette-index', index);
|
||||||
|
btnUp.addEventListener('click', () => {
|
||||||
|
if(index === 0) return;
|
||||||
|
const temp = palette[index - 1];
|
||||||
|
palette[index - 1] = palette[index];
|
||||||
|
palette[index] = temp;
|
||||||
|
updateOutput();
|
||||||
|
});
|
||||||
|
buttonArea.appendChild(btnUp);
|
||||||
|
|
||||||
|
const btnDown = document.createElement('button');
|
||||||
|
btnDown.textContent = '↓';
|
||||||
|
btnDown.setAttribute('data-palette-index', index);
|
||||||
|
btnDown.addEventListener('click', () => {
|
||||||
|
if(index === palette.length - 1) return;
|
||||||
|
const temp = palette[index + 1];
|
||||||
|
palette[index + 1] = palette[index];
|
||||||
|
palette[index] = temp;
|
||||||
|
updateOutput();
|
||||||
|
});
|
||||||
|
buttonArea.appendChild(btnDown);
|
||||||
|
|
||||||
|
const footer = document.createElement('div');
|
||||||
|
footer.appendChild(colorArea);
|
||||||
|
footer.appendChild(buttonArea);
|
||||||
|
|
||||||
|
entry.appendChild(header);
|
||||||
|
entry.appendChild(footer);
|
||||||
|
elPaletteEntries.appendChild(entry);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Image ready?
|
||||||
|
if(!imageWidth || !imageHeight) return;
|
||||||
|
|
||||||
|
// Update indexed image preview
|
||||||
|
elOutputPreview.width = imageWidth;
|
||||||
|
elOutputPreview.height = imageHeight;
|
||||||
|
const outputCtx = elOutputPreview.getContext('2d');
|
||||||
|
const outputImageData = outputCtx.createImageData(imageWidth, imageHeight);
|
||||||
|
const outputData = outputImageData.data;
|
||||||
|
indexedImage.forEach((index, i) => {
|
||||||
|
let color;
|
||||||
|
if(palette.length <= index) {
|
||||||
|
elOutputError.textContent = `Indexed image references non-existent palette index ${index}.`;
|
||||||
|
elOutputError.style.display = 'block';
|
||||||
|
color = [0, 0, 0, 0];
|
||||||
|
} else {
|
||||||
|
color = palette[index];
|
||||||
|
}
|
||||||
|
outputData[i * 4] = color[0];
|
||||||
|
outputData[i * 4 + 1] = color[1];
|
||||||
|
outputData[i * 4 + 2] = color[2];
|
||||||
|
outputData[i * 4 + 3] = color[3];
|
||||||
|
});
|
||||||
|
outputCtx.putImageData(outputImageData, 0, 0);
|
||||||
|
|
||||||
|
if(elOutputError.style.display === 'none') {;
|
||||||
|
const unusedPaletteIndexes = palette.map((color, index) => {
|
||||||
|
return indexedImage.includes(index) ? null : index;
|
||||||
|
}).filter(Boolean);
|
||||||
|
if(unusedPaletteIndexes.length > 0) {
|
||||||
|
elOutputError.textContent = `Image does not use palette colors; ${unusedPaletteIndexes.join(', ')}.`;
|
||||||
|
elOutputError.style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rescale canvas
|
||||||
|
const scale = parseInt(elPreviewScale.value) || 1;
|
||||||
|
elOutputPreview.style.width = `${imageWidth * scale}px`;
|
||||||
|
elOutputPreview.style.height = `${imageHeight * scale}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const onImage = img => {
|
||||||
|
if(!img) return onBadFile('Failed to load image');
|
||||||
|
|
||||||
|
elError.style.display = 'none';
|
||||||
|
imageWidth = img.width;
|
||||||
|
imageHeight = img.height;
|
||||||
|
indexedImage = [];
|
||||||
|
|
||||||
|
// Update input preview
|
||||||
|
elInputPreview.width = imageWidth;
|
||||||
|
elInputPreview.height = imageHeight;
|
||||||
|
const ctx = elInputPreview.getContext('2d');
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
|
||||||
|
// Source palette from input image
|
||||||
|
palette = sourcePaletteFromImage(img);
|
||||||
|
|
||||||
|
// Index the image
|
||||||
|
const imageData = ctx.getImageData(0, 0, imageWidth, imageHeight);
|
||||||
|
const data = imageData.data;
|
||||||
|
for(let i = 0; i < data.length; i += 4) {
|
||||||
|
const color = [ data[i], data[i + 1], data[i + 2], data[i + 3] ];
|
||||||
|
const colorIndex = palette.findIndex(c => c[0] === color[0] && c[1] === color[1] && c[2] === color[2] && c[3] === color[3]);
|
||||||
|
indexedImage.push(colorIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPalettizedImage = dataView => {
|
||||||
|
if(!dataView) return onBadFile('Failed to load image');
|
||||||
|
|
||||||
|
// Ensure DPT and ver is 1
|
||||||
|
if(dataView.getUint8(0) !== 0x44 || dataView.getUint8(1) !== 0x50 || dataView.getUint8(2) !== 0x54 || dataView.getUint8(3) !== 0x01) {
|
||||||
|
return onBadFile('Invalid DPT file. Expected header "DPT" and version 1.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Width and Height
|
||||||
|
elError.style.display = 'none';
|
||||||
|
imageWidth = dataView.getUint32(3);
|
||||||
|
imageHeight = dataView.getUint32(7);
|
||||||
|
|
||||||
|
if(imageWidth <= 0 || imageHeight <= 0) {
|
||||||
|
return onBadFile('Invalid image dimensions in DPT file.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dataView.byteLength < 11 + imageWidth * imageHeight) {
|
||||||
|
return onBadFile('DPT file does not contain enough data for the specified dimensions.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const uniqueIndexes = []
|
||||||
|
|
||||||
|
// Image data
|
||||||
|
indexedImage = [];
|
||||||
|
for(let i = 11; i < dataView.byteLength; i++) {
|
||||||
|
const index = dataView.getUint8(i);
|
||||||
|
if(!uniqueIndexes.includes(index)) uniqueIndexes.push(index);
|
||||||
|
indexedImage.push(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const adhocPalette = [];
|
||||||
|
for(let i = 0; i < uniqueIndexes.length; i++) {
|
||||||
|
const index = uniqueIndexes[i];
|
||||||
|
// Get the most different possible color for this index
|
||||||
|
const color = [
|
||||||
|
(index * 37) % 256,
|
||||||
|
(index * 61) % 256,
|
||||||
|
(index * 97) % 256,
|
||||||
|
255
|
||||||
|
];
|
||||||
|
adhocPalette[index] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
elInputPreview.width = imageWidth;
|
||||||
|
elInputPreview.height = imageHeight;
|
||||||
|
const ctx = elInputPreview.getContext('2d');
|
||||||
|
const imageData = ctx.createImageData(imageWidth, imageHeight);
|
||||||
|
const data = imageData.data;
|
||||||
|
indexedImage.forEach((index, i) => {
|
||||||
|
const color = adhocPalette[index] || [0, 0, 0, 0];
|
||||||
|
data[i * 4] = color[0];
|
||||||
|
data[i * 4 + 1] = color[1];
|
||||||
|
data[i * 4 + 2] = color[2];
|
||||||
|
data[i * 4 + 3] = color[3];
|
||||||
|
});
|
||||||
|
ctx.putImageData(imageData, 0, 0);
|
||||||
|
|
||||||
|
updateOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBadFile = err => {
|
||||||
|
elError.textContent = err;
|
||||||
|
elError.style.display = 'block';
|
||||||
|
updateOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
const onFile = file => {
|
||||||
|
// Reset preview
|
||||||
|
elInputPreview.width = 0;
|
||||||
|
elInputPreview.height = 0;
|
||||||
|
image = null;
|
||||||
|
|
||||||
|
if(!file) {
|
||||||
|
onImage(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If file is image, load as image.
|
||||||
|
if(file.type.startsWith('image/')) {
|
||||||
|
elError.style.display = 'none';
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (event) => {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => onImage(img);
|
||||||
|
img.onerror = () => onImage(null);
|
||||||
|
img.src = event.target.result;
|
||||||
|
};
|
||||||
|
reader.onerror = () => onImage(null);
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else if(file.name.endsWith('.dpt')) {
|
||||||
|
elError.style.display = 'none';
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (event) => {
|
||||||
|
const arrayBuffer = event.target.result;
|
||||||
|
const dataView = new DataView(arrayBuffer);
|
||||||
|
onPalettizedImage(dataView);
|
||||||
|
};
|
||||||
|
reader.onerror = () => onPalettizedImage(null);
|
||||||
|
reader.readAsArrayBuffer(file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onBadFile('Selected file is not a supported image type.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listeners
|
||||||
|
btnBackgroundWhite.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'white';
|
||||||
|
});
|
||||||
|
btnBackgroundTransparent.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'black';
|
||||||
|
});
|
||||||
|
btnBackgroundCheckerboard.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'repeating-conic-gradient(#ccc 0% 25%, #eee 0% 50%) 50% / 20px 20px';
|
||||||
|
});
|
||||||
|
btnBackgroundMagenta.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'magenta';
|
||||||
|
});
|
||||||
|
btnBackgroundBlue.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'blue';
|
||||||
|
});
|
||||||
|
btnBackgroundGreen.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'green';
|
||||||
|
});
|
||||||
|
|
||||||
|
elFile.addEventListener('change', (event) => {
|
||||||
|
onFile(event?.target?.files[0]);
|
||||||
|
});
|
||||||
|
elPaletteAdd.addEventListener('click', () => {
|
||||||
|
// Add new random color to palette
|
||||||
|
const newColor = [ Math.floor(Math.random() * 256), Math.floor(Math.random() * 256), Math.floor(Math.random() * 256), 255 ];
|
||||||
|
palette.push(newColor);
|
||||||
|
updateOutput();
|
||||||
|
});
|
||||||
|
elPreviewScale.addEventListener('change', () => {
|
||||||
|
updateOutput();
|
||||||
|
});
|
||||||
|
elClearPalette.addEventListener('click', () => {
|
||||||
|
palette = [];
|
||||||
|
updateOutput();
|
||||||
|
});
|
||||||
|
|
||||||
|
elOptimizePalette.addEventListener('click', () => {
|
||||||
|
// Remove unused colors and duplicates from the palette. Treat A=0 as equal
|
||||||
|
const newPalette = [];
|
||||||
|
const indexMap = {};
|
||||||
|
palette.forEach((color, index) => {
|
||||||
|
// Check if color is already in new palette
|
||||||
|
const existingIndex = newPalette.findIndex(c => {
|
||||||
|
if(c[3] === 0 && color[3] === 0) return true;
|
||||||
|
return c[0] === color[0] && c[1] === color[1] && c[2] === color[2] && c[3] === color[3];
|
||||||
|
});
|
||||||
|
if(existingIndex !== -1) {
|
||||||
|
indexMap[index] = existingIndex;
|
||||||
|
} else {
|
||||||
|
indexMap[index] = newPalette.length;
|
||||||
|
newPalette.push(color);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
palette = newPalette;
|
||||||
|
|
||||||
|
updateOutput();
|
||||||
|
});
|
||||||
|
|
||||||
|
elAppendPalette.addEventListener('click', () => {
|
||||||
|
// Open file picker
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'file';
|
||||||
|
input.addEventListener('change', (event) => {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
if(!file) return;
|
||||||
|
|
||||||
|
// Accept either images or .dpf files
|
||||||
|
if(file.type.startsWith('image/')) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (event) => {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
const newColors = sourcePaletteFromImage(img);
|
||||||
|
palette = palette.concat(newColors);
|
||||||
|
updateOutput();
|
||||||
|
};
|
||||||
|
img.onerror = () => {
|
||||||
|
alert('Failed to load image for palette appending.');
|
||||||
|
};
|
||||||
|
img.src = event.target.result;
|
||||||
|
};
|
||||||
|
reader.onerror = () => {
|
||||||
|
alert('Failed to load image for palette appending.');
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
return;
|
||||||
|
} else if(file.name.endsWith('.dpf')) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (event) => {
|
||||||
|
const arrayBuffer = event.target.result;
|
||||||
|
const dataView = new DataView(arrayBuffer);
|
||||||
|
|
||||||
|
// Validate header
|
||||||
|
if(dataView.getUint8(0) !== 0x44 || dataView.getUint8(1) !== 0x50 || dataView.getUint8(2) !== 0x46) {
|
||||||
|
alert('Invalid DPF file.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const colorCount = dataView.getUint32(4);
|
||||||
|
const expectedLength = 4 * colorCount + 8;// 3 DPF, 1 ver, 4 color count
|
||||||
|
if(arrayBuffer.byteLength !== expectedLength) {
|
||||||
|
alert('DPF file size does not match expected color count.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let offset = 8;
|
||||||
|
for(let i = 0; i < colorCount; i++) {
|
||||||
|
const r = dataView.getUint8(offset);
|
||||||
|
const g = dataView.getUint8(offset + 1);
|
||||||
|
const b = dataView.getUint8(offset + 2);
|
||||||
|
const a = dataView.getUint8(offset + 3);
|
||||||
|
palette.push([r, g, b, a]);
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateOutput();
|
||||||
|
};
|
||||||
|
reader.onerror = () => {
|
||||||
|
alert('Failed to load DPF file for palette appending.');
|
||||||
|
};
|
||||||
|
reader.readAsArrayBuffer(file);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
alert('Unsupported file type for palette appending. Please use an image file.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
input.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
btnDownloadPalette.addEventListener('click', () => {
|
||||||
|
// Create Dusk Palette File (.dpf)
|
||||||
|
const header = new Uint8Array([0x44, 0x50, 0x46, 0x01]); // 'DPF' + version 1 + number of colors (4 bytes)
|
||||||
|
|
||||||
|
const colorCount = palette.length;
|
||||||
|
const colorCountBytes = new Uint8Array(4);
|
||||||
|
colorCountBytes[0] = (colorCount >> 24) & 0xFF;
|
||||||
|
colorCountBytes[1] = (colorCount >> 16) & 0xFF;
|
||||||
|
colorCountBytes[2] = (colorCount >> 8) & 0xFF;
|
||||||
|
colorCountBytes[3] = colorCount & 0xFF;
|
||||||
|
|
||||||
|
// add color data (palette.length * 4 bytes)
|
||||||
|
const colorData = new Uint8Array(palette.length * 4);
|
||||||
|
palette.forEach((color, index) => {
|
||||||
|
colorData[index * 4] = color[0];
|
||||||
|
colorData[index * 4 + 1] = color[1];
|
||||||
|
colorData[index * 4 + 2] = color[2];
|
||||||
|
colorData[index * 4 + 3] = color[3];
|
||||||
|
});
|
||||||
|
|
||||||
|
const blob = new Blob([header, colorCountBytes, colorData], { type: 'application/octet-stream' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = 'palette.dpf';
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
btnDownloadImage.addEventListener('click', () => {
|
||||||
|
const header = new Uint8Array([0x44, 0x50, 0x54, 0x01]); // 'DPT' + version 1
|
||||||
|
|
||||||
|
// Width
|
||||||
|
const widthBytes = new Uint8Array(4);
|
||||||
|
widthBytes[0] = (imageWidth >> 24) & 0xFF;
|
||||||
|
widthBytes[1] = (imageWidth >> 16) & 0xFF;
|
||||||
|
widthBytes[2] = (imageWidth >> 8) & 0xFF;
|
||||||
|
widthBytes[3] = imageWidth & 0xFF;
|
||||||
|
|
||||||
|
// Height
|
||||||
|
const heightBytes = new Uint8Array(4);
|
||||||
|
heightBytes[0] = (imageHeight >> 24) & 0xFF;
|
||||||
|
heightBytes[1] = (imageHeight >> 16) & 0xFF;
|
||||||
|
heightBytes[2] = (imageHeight >> 8) & 0xFF;
|
||||||
|
heightBytes[3] = imageHeight & 0xFF;
|
||||||
|
|
||||||
|
// add indexed image data (imageWidth * imageHeight bytes)
|
||||||
|
const imageData = new Uint8Array(indexedImage.length);
|
||||||
|
indexedImage.forEach((index, i) => {
|
||||||
|
imageData[i] = index;
|
||||||
|
});
|
||||||
|
|
||||||
|
const blob = new Blob([header, widthBytes, heightBytes, imageData], { type: 'application/octet-stream' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = 'indexed_image.dpt';
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
updateOutput();
|
||||||
|
btnBackgroundCheckerboard.click();
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import csv
|
import csv
|
||||||
from tools.util.type import detectType, stringToCType, typeToCType
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description="Story CSV to .h defines")
|
parser = argparse.ArgumentParser(description="Story CSV to .h defines")
|
||||||
parser.add_argument("--csv", required=True, help="Path to story CSV file")
|
parser.add_argument("--csv", required=True, help="Path to story CSV file")
|
||||||
|
|||||||
@@ -0,0 +1,223 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Dusk Tools / Tile Joiner</title>
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
image-rendering: pixelated;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Dusk Tile Joiner</h1>
|
||||||
|
<p>
|
||||||
|
Joins multiple tiles together into a single tileset image. Optimizing and
|
||||||
|
allowing it to work on multiple platforms. Output width and height will
|
||||||
|
always be a power of two. This tool will take a while to process images,
|
||||||
|
since all images need to be loaded into memory.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<input type="file" data-file-input multiple />
|
||||||
|
</div>
|
||||||
|
<p data-file-error style="color:red;display:none;"></p>
|
||||||
|
<textarea readonly data-input-information rows="10" style="width:500px"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>Settings</h2>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
Preview Background:
|
||||||
|
<button data-page-bg-white>White</button>
|
||||||
|
<button data-page-bg-transparent>Black</button>
|
||||||
|
<button data-page-bg-checkerboard>Checkerboard</button>
|
||||||
|
<button data-page-bg-magenta>Magenta</button>
|
||||||
|
<button data-page-bg-blue>Blue</button>
|
||||||
|
<button data-page-bg-green>Green</button>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>Joined Preview</h2>
|
||||||
|
<div>
|
||||||
|
<button data-download>Download Joined Image</button>
|
||||||
|
</div>
|
||||||
|
<canvas data-preview-canvas style="border:1px solid black;"></canvas>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
const elFileInput = document.querySelector('[data-file-input]');
|
||||||
|
const elFileError = document.querySelector('[data-file-error]');
|
||||||
|
const elInputInformation = document.querySelector('[data-input-information]');
|
||||||
|
const elPreviewCanvas = document.querySelector('[data-preview-canvas]');
|
||||||
|
const btnDownload = document.querySelector('[data-download]');
|
||||||
|
const btnBackgroundWhite = document.querySelector('[data-page-bg-white]');
|
||||||
|
const btnBackgroundTransparent = document.querySelector('[data-page-bg-transparent]');
|
||||||
|
const btnBackgroundCheckerboard = document.querySelector('[data-page-bg-checkerboard]');
|
||||||
|
const btnBackgroundMagenta = document.querySelector('[data-page-bg-magenta]');
|
||||||
|
const btnBackgroundBlue = document.querySelector('[data-page-bg-blue]');
|
||||||
|
const btnBackgroundGreen = document.querySelector('[data-page-bg-green]');
|
||||||
|
|
||||||
|
let images = {};
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
const nextPowerOfTwo = n => {
|
||||||
|
if(n <= 0) return 1;
|
||||||
|
return 2 ** Math.ceil(Math.log2(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBadImages = error => {
|
||||||
|
elInputInformation.value = '';
|
||||||
|
elFileError.style.display = 'block';
|
||||||
|
elFileError.textContent = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const onImages = () => {
|
||||||
|
if(!images || Object.keys(images).length <= 1) {
|
||||||
|
return onBadImages('Please select 2 or more image images.');
|
||||||
|
}
|
||||||
|
|
||||||
|
elFileError.style.display = 'none';
|
||||||
|
|
||||||
|
let strInfo = `Selected ${Object.keys(images).length} images:\n`;
|
||||||
|
for(const [name, img] of Object.entries(images)) {
|
||||||
|
strInfo += `- ${name}: ${img.width}x${img.height}\n`;
|
||||||
|
}
|
||||||
|
elInputInformation.value = strInfo;
|
||||||
|
|
||||||
|
// Determine output width and height to pack images together, must be a
|
||||||
|
// power of two. If all images share a given axis (width/height) and that
|
||||||
|
// axis is already a power of two, use that.
|
||||||
|
const firstWidth = Object.values(images)[0].width;
|
||||||
|
const firstHeight = Object.values(images)[0].height;
|
||||||
|
let allImagesShareWidth = Object.values(images).every(img => img.width === firstWidth);
|
||||||
|
let allImagesShareHeight = Object.values(images).every(img => img.height === firstHeight);
|
||||||
|
|
||||||
|
let outputHeight, outputWidth;
|
||||||
|
|
||||||
|
if(allImagesShareWidth && nextPowerOfTwo(firstWidth) === firstWidth) {
|
||||||
|
outputWidth = firstWidth;
|
||||||
|
outputHeight = nextPowerOfTwo(Object.values(images).reduce((sum, img) => sum + img.height, 0));
|
||||||
|
} else if(allImagesShareHeight && nextPowerOfTwo(firstHeight) === firstHeight) {
|
||||||
|
outputHeight = firstHeight;
|
||||||
|
outputWidth = nextPowerOfTwo(Object.values(images).reduce((sum, img) => sum + img.width, 0));
|
||||||
|
} else {
|
||||||
|
onBadImages('All images must share the same width or height, and that dimension must be a power of two.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update preview
|
||||||
|
elPreviewCanvas.width = outputWidth;
|
||||||
|
elPreviewCanvas.height = outputHeight;
|
||||||
|
const ctx = elPreviewCanvas.getContext('2d');
|
||||||
|
let currentX = 0;
|
||||||
|
let currentY = 0;
|
||||||
|
for(const img of Object.values(images)) {
|
||||||
|
ctx.drawImage(img, currentX, currentY);
|
||||||
|
if(allImagesShareWidth) {
|
||||||
|
currentY += img.height;
|
||||||
|
} else {
|
||||||
|
currentX += img.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onFiles = async files => {
|
||||||
|
images = {};
|
||||||
|
|
||||||
|
if(!files || files.length <= 1) {
|
||||||
|
return onBadImages('Please select 2 or more image files.');
|
||||||
|
}
|
||||||
|
|
||||||
|
let strError = '';
|
||||||
|
for(const file of files) {
|
||||||
|
if(!file.type.startsWith('image/')) {
|
||||||
|
strError += `File is not an image: ${file.name}\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(strError) {
|
||||||
|
return onBadImages(strError);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const fileImages = await Promise.all(Array.from(files).map(file => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = event => {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
images[file.name] = img;
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
img.onerror = () => {
|
||||||
|
reject(`Failed to load image: ${file.name}`);
|
||||||
|
}
|
||||||
|
img.src = event.target.result;
|
||||||
|
}
|
||||||
|
reader.onerror = () => {
|
||||||
|
reject(`Failed to read file: ${file.name}`);
|
||||||
|
}
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
} catch(error) {
|
||||||
|
return onBadImages(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
onImages();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listeners
|
||||||
|
elFileInput.addEventListener('change', event => {
|
||||||
|
onFiles(event?.target?.files);
|
||||||
|
});
|
||||||
|
|
||||||
|
btnBackgroundWhite.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'white';
|
||||||
|
});
|
||||||
|
btnBackgroundTransparent.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'black';
|
||||||
|
});
|
||||||
|
btnBackgroundCheckerboard.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'repeating-conic-gradient(#ccc 0% 25%, #eee 0% 50%) 50% / 20px 20px';
|
||||||
|
});
|
||||||
|
btnBackgroundMagenta.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'magenta';
|
||||||
|
});
|
||||||
|
btnBackgroundBlue.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'blue';
|
||||||
|
});
|
||||||
|
btnBackgroundGreen.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'green';
|
||||||
|
});
|
||||||
|
|
||||||
|
btnDownload.addEventListener('click', () => {
|
||||||
|
if(!images || Object.keys(images).length <= 1) {
|
||||||
|
return onBadImages('Please select 2 or more image files before downloading.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.download = 'joined.png';
|
||||||
|
link.href = elPreviewCanvas.toDataURL();
|
||||||
|
link.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
btnBackgroundCheckerboard.click();
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,391 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Dusk Tools / Tile Slicer</title>
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
image-rendering: pixelated;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Dusk Tile Slicer</h1>
|
||||||
|
<p>
|
||||||
|
Tool allows you to take a single image and slice it into individual tiles.
|
||||||
|
This should be done as the first step of optimizing tilesets for your
|
||||||
|
dusk game.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<input type="file" data-file-input />
|
||||||
|
</div>
|
||||||
|
<p data-file-error style="color:red;display:none;"></p>
|
||||||
|
|
||||||
|
<h2>Input Preview</h2>
|
||||||
|
<canvas data-input-preview style="border:1px solid black;"></canvas>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>Settings</h2>
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
Tile Width:
|
||||||
|
<input type="number" value="8" data-tile-width />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
Tile Height:
|
||||||
|
<input type="number" value="8" data-tile-height />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
Padding:
|
||||||
|
<input type="number" value="0" data-tile-padding />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
Margin:
|
||||||
|
<input type="number" value="0" data-tile-margin />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
Remove Duplicate Tiles:
|
||||||
|
<input type="checkbox" data-remove-duplicates checked />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
Remove Empty Tiles:
|
||||||
|
<input type="checkbox" data-remove-empty checked />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
Preview Background:
|
||||||
|
<button data-page-bg-white>White</button>
|
||||||
|
<button data-page-bg-transparent>Black</button>
|
||||||
|
<button data-page-bg-checkerboard>Checkerboard</button>
|
||||||
|
<button data-page-bg-magenta>Magenta</button>
|
||||||
|
<button data-page-bg-blue>Blue</button>
|
||||||
|
<button data-page-bg-green>Green</button>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>Sliced Preview</h2>
|
||||||
|
<div data-output-preview></div>
|
||||||
|
<div data-output-hover></div>
|
||||||
|
<textarea readonly data-output-information rows="10" style="width:500px"></textarea>
|
||||||
|
<div>
|
||||||
|
<button data-download-archive>Download All Tiles</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
const elError = document.querySelector('[data-file-error]');
|
||||||
|
const elFile = document.querySelector('[data-file-input]');
|
||||||
|
const elInputPreview = document.querySelector('[data-input-preview]');
|
||||||
|
const elOutputPreview = document.querySelector('[data-output-preview]');
|
||||||
|
const elTileWidth = document.querySelector('[data-tile-width]');
|
||||||
|
const elTileHeight = document.querySelector('[data-tile-height]');
|
||||||
|
const elTilePadding = document.querySelector('[data-tile-padding]');
|
||||||
|
const elTileMargin = document.querySelector('[data-tile-margin]');
|
||||||
|
const elRemoveDuplicates = document.querySelector('[data-remove-duplicates]');
|
||||||
|
const elRemoveEmpty = document.querySelector('[data-remove-empty]');
|
||||||
|
const elOutputInformation = document.querySelector('[data-output-information]');
|
||||||
|
const btnBackgroundWhite = document.querySelector('[data-page-bg-white]');
|
||||||
|
const btnBackgroundTransparent = document.querySelector('[data-page-bg-transparent]');
|
||||||
|
const btnBackgroundCheckerboard = document.querySelector('[data-page-bg-checkerboard]');
|
||||||
|
const btnBackgroundMagenta = document.querySelector('[data-page-bg-magenta]');
|
||||||
|
const btnBackgroundBlue = document.querySelector('[data-page-bg-blue]');
|
||||||
|
const btnBackgroundGreen = document.querySelector('[data-page-bg-green]');
|
||||||
|
const btnDownloadTiles = document.querySelector('[data-download-archive]');
|
||||||
|
|
||||||
|
let image = null;
|
||||||
|
let tileCanvases = [];
|
||||||
|
|
||||||
|
// Values updated during processing
|
||||||
|
let cols, rows;
|
||||||
|
let tileWidth, tileHeight;
|
||||||
|
let tilePadding, tileMargin;
|
||||||
|
let emptyTiles, duplicateTiles;
|
||||||
|
let hoveredTileX = -1, hoveredTileY = -1;
|
||||||
|
let tileStatus = {};
|
||||||
|
|
||||||
|
const updateOutputInformation = () => {
|
||||||
|
if(!image) {
|
||||||
|
elOutputInformation.value = 'No image loaded';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
elOutputInformation.value = [
|
||||||
|
`Input Tile Count: ${cols * rows}`,
|
||||||
|
`Output Tile Count: ${tileCanvases.length}`,
|
||||||
|
elRemoveEmpty.checked ? `Empty Tiles Removed: ${emptyTiles}` : null,
|
||||||
|
elRemoveDuplicates.checked ? `Duplicate Tiles Removed: ${duplicateTiles}` : null,
|
||||||
|
hoveredTileX >= 0 && hoveredTileY >= 0 ? `Hovered tile: (${hoveredTileX}, ${hoveredTileY}) (Index ${hoveredTileX + hoveredTileY * cols})` : null,
|
||||||
|
tileStatus[hoveredTileY * cols + hoveredTileX] || null
|
||||||
|
].filter(Boolean).join('\n');
|
||||||
|
|
||||||
|
elOutputPreview.querySelectorAll('canvas').forEach(canvas => {
|
||||||
|
const x = parseInt(canvas.getAttribute('data-tile-x'), 10);
|
||||||
|
const y = parseInt(canvas.getAttribute('data-tile-y'), 10);
|
||||||
|
const isHovered = x === hoveredTileX && y === hoveredTileY;
|
||||||
|
|
||||||
|
canvas.style.border = `1px solid ${isHovered ? 'red' : 'black'}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateOutput = () => {
|
||||||
|
// Clear previous output
|
||||||
|
elOutputPreview.innerHTML = '';
|
||||||
|
tileCanvases = [];
|
||||||
|
btnDownloadTiles.disabled = true;
|
||||||
|
hoveredTileX = -1;
|
||||||
|
hoveredTileY = -1;
|
||||||
|
|
||||||
|
// Image ready?
|
||||||
|
if(!image) {
|
||||||
|
updateOutputInformation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each tile, create a canvas and draw the tile on it
|
||||||
|
tileWidth = parseInt(elTileWidth.value, 10);
|
||||||
|
tileHeight = parseInt(elTileHeight.value, 10);
|
||||||
|
tilePadding = parseInt(elTilePadding.value, 10);
|
||||||
|
tileMargin = parseInt(elTileMargin.value, 10);
|
||||||
|
cols = Math.floor((image.width - tileMargin * 2 + tilePadding) / (tileWidth + tilePadding));
|
||||||
|
rows = Math.floor((image.height - tileMargin * 2 + tilePadding) / (tileHeight + tilePadding));
|
||||||
|
|
||||||
|
if(isNaN(cols) || isNaN(rows) || cols <= 0 || rows <= 0) {
|
||||||
|
elError.textContent = 'Invalid tile settings for the given image';
|
||||||
|
elError.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emptyTiles = 0;
|
||||||
|
duplicateTiles = 0;
|
||||||
|
oldIndexToNewIndex = {};
|
||||||
|
tileStatus = {};
|
||||||
|
for(let y = 0; y < rows; y++) {
|
||||||
|
for(let x = 0; x < cols; x++) {
|
||||||
|
const tileCanvas = document.createElement('canvas');
|
||||||
|
tileCanvas.width = tileWidth;
|
||||||
|
tileCanvas.height = tileHeight;
|
||||||
|
const ctx = tileCanvas.getContext('2d');
|
||||||
|
ctx.drawImage(
|
||||||
|
image,
|
||||||
|
tileMargin + x * (tileWidth + tilePadding),
|
||||||
|
tileMargin + y * (tileHeight + tilePadding),
|
||||||
|
tileWidth,
|
||||||
|
tileHeight,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
tileWidth,
|
||||||
|
tileHeight
|
||||||
|
);
|
||||||
|
tileCanvas.setAttribute('data-tile-x', x);
|
||||||
|
tileCanvas.setAttribute('data-tile-y', y);
|
||||||
|
|
||||||
|
// Empty check.
|
||||||
|
if(elRemoveEmpty.checked) {
|
||||||
|
const imageData = ctx.getImageData(0, 0, tileWidth, tileHeight);
|
||||||
|
const isEmpty = !imageData.data.some(channel => channel !== 0);
|
||||||
|
if(isEmpty) {
|
||||||
|
tileStatus[y * cols + x] = 'Removed (Empty)';
|
||||||
|
emptyTiles++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(elRemoveDuplicates.checked) {
|
||||||
|
const tileDataURL = tileCanvas.toDataURL();
|
||||||
|
const duplicateIndex = tileCanvases.findIndex(canvas => canvas.toDataURL() === tileDataURL);
|
||||||
|
if(duplicateIndex !== -1) {
|
||||||
|
tileStatus[y * cols + x] = `Removed (Duplicate of ${duplicateIndex})`;
|
||||||
|
duplicateTiles++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tileCanvases.push(tileCanvas);
|
||||||
|
elOutputPreview.appendChild(tileCanvas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
btnDownloadTiles.disabled = false;
|
||||||
|
updateOutputInformation();
|
||||||
|
}
|
||||||
|
|
||||||
|
const onImage = img => {
|
||||||
|
elError.style.display = 'none';
|
||||||
|
image = img;
|
||||||
|
|
||||||
|
// Update input preview
|
||||||
|
elInputPreview.width = img.width;
|
||||||
|
elInputPreview.height = img.height;
|
||||||
|
const ctx = elInputPreview.getContext('2d');
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
|
||||||
|
updateOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
const onBadFile = err => {
|
||||||
|
elError.textContent = err;
|
||||||
|
elError.style.display = 'block';
|
||||||
|
updateOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
const onFile = file => {
|
||||||
|
// Reset preview
|
||||||
|
elInputPreview.width = 0;
|
||||||
|
elInputPreview.height = 0;
|
||||||
|
image = null;
|
||||||
|
|
||||||
|
if(!file) {
|
||||||
|
onBadFile('No file selected');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!file.type.startsWith('image/')) {
|
||||||
|
onBadFile('Selected file is not an image');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
elError.style.display = 'none';
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (event) => {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => onImage(img);
|
||||||
|
img.onerror = () => onBadFile('Failed to load image');
|
||||||
|
img.src = event.target.result;
|
||||||
|
};
|
||||||
|
reader.onerror = () => onBadFile('Failed to read file');
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
updateOutput();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listeners
|
||||||
|
elFile.addEventListener('change', (event) => {
|
||||||
|
onFile(event?.target?.files[0]);
|
||||||
|
});
|
||||||
|
elTileWidth.addEventListener('input', updateOutput);
|
||||||
|
elTileHeight.addEventListener('input', updateOutput);
|
||||||
|
elTilePadding.addEventListener('input', updateOutput);
|
||||||
|
elTileMargin.addEventListener('input', updateOutput);
|
||||||
|
elRemoveEmpty.addEventListener('change', updateOutput);
|
||||||
|
elRemoveDuplicates.addEventListener('change', updateOutput);
|
||||||
|
|
||||||
|
btnBackgroundWhite.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'white';
|
||||||
|
});
|
||||||
|
btnBackgroundTransparent.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'black';
|
||||||
|
});
|
||||||
|
btnBackgroundCheckerboard.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'repeating-conic-gradient(#ccc 0% 25%, #eee 0% 50%) 50% / 20px 20px';
|
||||||
|
});
|
||||||
|
btnBackgroundMagenta.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'magenta';
|
||||||
|
});
|
||||||
|
btnBackgroundBlue.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'blue';
|
||||||
|
});
|
||||||
|
btnBackgroundGreen.addEventListener('click', () => {
|
||||||
|
document.body.style.background = 'green';
|
||||||
|
});
|
||||||
|
|
||||||
|
btnDownloadTiles.addEventListener('click', () => {
|
||||||
|
if(tileCanvases.length === 0) {
|
||||||
|
alert('No tiles to download');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const zip = new JSZip();
|
||||||
|
tileCanvases.forEach((canvas, index) => {
|
||||||
|
const dataURL = canvas.toDataURL('image/png');
|
||||||
|
const base64Data = dataURL.split(',')[1];
|
||||||
|
zip.file(`tile_${index}.png`, base64Data, {base64: true});
|
||||||
|
});
|
||||||
|
|
||||||
|
zip.generateAsync({type: 'blob'}).then(content => {
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = URL.createObjectURL(content);
|
||||||
|
link.download = 'tiles.zip';
|
||||||
|
link.click();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// On mouse move of input preview
|
||||||
|
elInputPreview.addEventListener('mousemove', (event) => {
|
||||||
|
if(!image || elError.style.display !== 'none') return;
|
||||||
|
|
||||||
|
const rect = elInputPreview.getBoundingClientRect();
|
||||||
|
const x = event.clientX - rect.left;
|
||||||
|
const y = event.clientY - rect.top;
|
||||||
|
|
||||||
|
hoveredTileX = Math.floor((x - tileMargin) / (tileWidth + tilePadding));
|
||||||
|
hoveredTileY = Math.floor((y - tileMargin) / (tileHeight + tilePadding));
|
||||||
|
|
||||||
|
updateOutputInformation();
|
||||||
|
});
|
||||||
|
elInputPreview.addEventListener('mouseleave', () => {
|
||||||
|
hoveredTileX = -1;
|
||||||
|
hoveredTileY = -1;
|
||||||
|
updateOutputInformation();
|
||||||
|
});
|
||||||
|
|
||||||
|
updateOutput();
|
||||||
|
btnBackgroundCheckerboard.click();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
/*!
|
||||||
|
JSZip v3.10.1 - A JavaScript class for generating and reading zip files
|
||||||
|
<http://stuartk.com/jszip>
|
||||||
|
|
||||||
|
(c) 2009-2016 Stuart Knightley <stuart [at] stuartk.com>
|
||||||
|
Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/main/LICENSE.markdown.
|
||||||
|
|
||||||
|
JSZip uses the library pako released under the MIT license :
|
||||||
|
https://github.com/nodeca/pako/blob/main/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).JSZip=e()}}(function(){return function s(a,o,h){function u(r,e){if(!o[r]){if(!a[r]){var t="function"==typeof require&&require;if(!e&&t)return t(r,!0);if(l)return l(r,!0);var n=new Error("Cannot find module '"+r+"'");throw n.code="MODULE_NOT_FOUND",n}var i=o[r]={exports:{}};a[r][0].call(i.exports,function(e){var t=a[r][1][e];return u(t||e)},i,i.exports,s,a,o,h)}return o[r].exports}for(var l="function"==typeof require&&require,e=0;e<h.length;e++)u(h[e]);return u}({1:[function(e,t,r){"use strict";var d=e("./utils"),c=e("./support"),p="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";r.encode=function(e){for(var t,r,n,i,s,a,o,h=[],u=0,l=e.length,f=l,c="string"!==d.getTypeOf(e);u<e.length;)f=l-u,n=c?(t=e[u++],r=u<l?e[u++]:0,u<l?e[u++]:0):(t=e.charCodeAt(u++),r=u<l?e.charCodeAt(u++):0,u<l?e.charCodeAt(u++):0),i=t>>2,s=(3&t)<<4|r>>4,a=1<f?(15&r)<<2|n>>6:64,o=2<f?63&n:64,h.push(p.charAt(i)+p.charAt(s)+p.charAt(a)+p.charAt(o));return h.join("")},r.decode=function(e){var t,r,n,i,s,a,o=0,h=0,u="data:";if(e.substr(0,u.length)===u)throw new Error("Invalid base64 input, it looks like a data url.");var l,f=3*(e=e.replace(/[^A-Za-z0-9+/=]/g,"")).length/4;if(e.charAt(e.length-1)===p.charAt(64)&&f--,e.charAt(e.length-2)===p.charAt(64)&&f--,f%1!=0)throw new Error("Invalid base64 input, bad content length.");for(l=c.uint8array?new Uint8Array(0|f):new Array(0|f);o<e.length;)t=p.indexOf(e.charAt(o++))<<2|(i=p.indexOf(e.charAt(o++)))>>4,r=(15&i)<<4|(s=p.indexOf(e.charAt(o++)))>>2,n=(3&s)<<6|(a=p.indexOf(e.charAt(o++))),l[h++]=t,64!==s&&(l[h++]=r),64!==a&&(l[h++]=n);return l}},{"./support":30,"./utils":32}],2:[function(e,t,r){"use strict";var n=e("./external"),i=e("./stream/DataWorker"),s=e("./stream/Crc32Probe"),a=e("./stream/DataLengthProbe");function o(e,t,r,n,i){this.compressedSize=e,this.uncompressedSize=t,this.crc32=r,this.compression=n,this.compressedContent=i}o.prototype={getContentWorker:function(){var e=new i(n.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new a("data_length")),t=this;return e.on("end",function(){if(this.streamInfo.data_length!==t.uncompressedSize)throw new Error("Bug : uncompressed data size mismatch")}),e},getCompressedWorker:function(){return new i(n.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize",this.compressedSize).withStreamInfo("uncompressedSize",this.uncompressedSize).withStreamInfo("crc32",this.crc32).withStreamInfo("compression",this.compression)}},o.createWorkerFrom=function(e,t,r){return e.pipe(new s).pipe(new a("uncompressedSize")).pipe(t.compressWorker(r)).pipe(new a("compressedSize")).withStreamInfo("compression",t)},t.exports=o},{"./external":6,"./stream/Crc32Probe":25,"./stream/DataLengthProbe":26,"./stream/DataWorker":27}],3:[function(e,t,r){"use strict";var n=e("./stream/GenericWorker");r.STORE={magic:"\0\0",compressWorker:function(){return new n("STORE compression")},uncompressWorker:function(){return new n("STORE decompression")}},r.DEFLATE=e("./flate")},{"./flate":7,"./stream/GenericWorker":28}],4:[function(e,t,r){"use strict";var n=e("./utils");var o=function(){for(var e,t=[],r=0;r<256;r++){e=r;for(var n=0;n<8;n++)e=1&e?3988292384^e>>>1:e>>>1;t[r]=e}return t}();t.exports=function(e,t){return void 0!==e&&e.length?"string"!==n.getTypeOf(e)?function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a<s;a++)e=e>>>8^i[255&(e^t[a])];return-1^e}(0|t,e,e.length,0):function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a<s;a++)e=e>>>8^i[255&(e^t.charCodeAt(a))];return-1^e}(0|t,e,e.length,0):0}},{"./utils":32}],5:[function(e,t,r){"use strict";r.base64=!1,r.binary=!1,r.dir=!1,r.createFolders=!0,r.date=null,r.compression=null,r.compressionOptions=null,r.comment=null,r.unixPermissions=null,r.dosPermissions=null},{}],6:[function(e,t,r){"use strict";var n=null;n="undefined"!=typeof Promise?Promise:e("lie"),t.exports={Promise:n}},{lie:37}],7:[function(e,t,r){"use strict";var n="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,i=e("pako"),s=e("./utils"),a=e("./stream/GenericWorker"),o=n?"uint8array":"array";function h(e,t){a.call(this,"FlateWorker/"+e),this._pako=null,this._pakoAction=e,this._pakoOptions=t,this.meta={}}r.magic="\b\0",s.inherits(h,a),h.prototype.processChunk=function(e){this.meta=e.meta,null===this._pako&&this._createPako(),this._pako.push(s.transformTo(o,e.data),!1)},h.prototype.flush=function(){a.prototype.flush.call(this),null===this._pako&&this._createPako(),this._pako.push([],!0)},h.prototype.cleanUp=function(){a.prototype.cleanUp.call(this),this._pako=null},h.prototype._createPako=function(){this._pako=new i[this._pakoAction]({raw:!0,level:this._pakoOptions.level||-1});var t=this;this._pako.onData=functLine truncated
|
||||||
|
name:e,dir:i,date:s,comment:t.comment||"",unixPermissions:t.unixPermissions,dosPermissions:t.dosPermissions}).pipe(o)}),o.entriesCount=h}catch(e){o.error(e)}return o}},{"../compressions":3,"./ZipFileWorker":8}],10:[function(e,t,r){"use strict";function n(){if(!(this instanceof n))return new n;if(arguments.length)throw new Error("The constructor with parameters has been removed in JSZip 3.0, please check the upgrade guide.");this.files=Object.create(null),this.comment=null,this.root="",this.clone=function(){var e=new n;for(var t in this)"function"!=typeof this[t]&&(e[t]=this[t]);return e}}(n.prototype=e("./object")).loadAsync=e("./load"),n.support=e("./support"),n.defaults=e("./defaults"),n.version="3.10.1",n.loadAsync=function(e,t){return(new n).loadAsync(e,t)},n.external=e("./external"),t.exports=n},{"./defaults":5,"./external":6,"./load":11,"./object":15,"./support":30}],11:[function(e,t,r){"use strict";var u=e("./utils"),i=e("./external"),n=e("./utf8"),s=e("./zipEntries"),a=e("./stream/Crc32Probe"),l=e("./nodejsUtils");function f(n){return new i.Promise(function(e,t){var r=n.decompressed.getContentWorker().pipe(new a);r.on("error",function(e){t(e)}).on("end",function(){r.streamInfo.crc32!==n.decompressed.crc32?t(new Error("Corrupted zip : CRC32 mismatch")):e()}).resume()})}t.exports=function(e,o){var h=this;return o=u.extend(o||{},{base64:!1,checkCRC32:!1,optimizedBinaryString:!1,createFolders:!1,decodeFileName:n.utf8decode}),l.isNode&&l.isStream(e)?i.Promise.reject(new Error("JSZip can't accept a stream when loading a zip file.")):u.prepareContent("the loaded zip file",e,!0,o.optimizedBinaryString,o.base64).then(function(e){var t=new s(o);return t.load(e),t}).then(function(e){var t=[i.Promise.resolve(e)],r=e.files;if(o.checkCRC32)for(var n=0;n<r.length;n++)t.push(f(r[n]));return i.Promise.all(t)}).then(function(e){for(var t=e.shift(),r=t.files,n=0;n<r.length;n++){var i=r[n],s=i.fileNameStr,a=u.resolve(i.fileNameStr);h.file(a,i.decompressed,{binary:!0,optimizedBinaryString:!0,date:i.date,dir:i.dir,comment:i.fileCommentStr.length?i.fileCommentStr:null,unixPermissions:i.unixPermissions,dosPermissions:i.dosPermissions,createFolders:o.createFolders}),i.dir||(h.file(a).unsafeOriginalName=s)}return t.zipComment.length&&(h.comment=t.zipComment),h})}},{"./external":6,"./nodejsUtils":14,"./stream/Crc32Probe":25,"./utf8":31,"./utils":32,"./zipEntries":33}],12:[function(e,t,r){"use strict";var n=e("../utils"),i=e("../stream/GenericWorker");function s(e,t){i.call(this,"Nodejs stream input adapter for "+e),this._upstreamEnded=!1,this._bindStream(t)}n.inherits(s,i),s.prototype._bindStream=function(e){var t=this;(this._stream=e).pause(),e.on("data",function(e){t.push({data:e,meta:{percent:0}})}).on("error",function(e){t.isPaused?this.generatedError=e:t.error(e)}).on("end",function(){t.isPaused?t._upstreamEnded=!0:t.end()})},s.prototype.pause=function(){return!!i.prototype.pause.call(this)&&(this._stream.pause(),!0)},s.prototype.resume=function(){return!!i.prototype.resume.call(this)&&(this._upstreamEnded?this.end():this._stream.resume(),!0)},t.exports=s},{"../stream/GenericWorker":28,"../utils":32}],13:[function(e,t,r){"use strict";var i=e("readable-stream").Readable;function n(e,t,r){i.call(this,t),this._helper=e;var n=this;e.on("data",function(e,t){n.push(e)||n._helper.pause(),r&&r(t)}).on("error",function(e){n.emit("error",e)}).on("end",function(){n.push(null)})}e("../utils").inherits(n,i),n.prototype._read=function(){this._helper.resume()},t.exports=n},{"../utils":32,"readable-stream":16}],14:[function(e,t,r){"use strict";t.exports={isNode:"undefined"!=typeof Buffer,newBufferFrom:function(e,t){if(Buffer.from&&Buffer.from!==Uint8Array.from)return Buffer.from(e,t);if("number"==typeof e)throw new Error('The "data" argument must not be a number');return new Buffer(e,t)},allocBuffer:function(e){if(Buffer.alloc)return Buffer.alloc(e);var t=new Buffer(e);return t.fill(0),t},isBuffer:function(e){return Buffer.isBuffer(e)},isStream:function(e){return e&&"function"==typeof e.on&&"function"==typeof e.pause&&"function"==typeof e.resume}}},{}],15:[function(e,t,r){"use strict";function s(e,t,r){var n,i=u.getTypeOf(t),s=u.extend(r||{},f);s.date=s.date||new Date,null!==s.compression&&(s.compression=s.compression.toUpperCase()),"string"==typeof s.unixPermissions&&(s.unixPermissions=parseInt(s.unixPermissions,8)),s.unixPermissions&&16384&s.unixPermissions&&(s.dir=!0),s.dosPermissions&&16&s.dosPermissions&&(s.dir=!0),s.dir&&(e=g(e)),s.createFolders&&(n=_(e))&&b.call(this,n,!0);var a="string"===i&&!1===s.binary&&!1===s.base64;r&&void 0!==r.binary||(s.binary=!a),(t instanceof c&&0===t.uncompressedSize||s.dir||!t||0===t.length)&&(s.base64=!1,s.binary=!0,t="",s.compression="STORE",i="string");var o=null;o=t instanceof c||t instanceof l?t:p.isNode&&p.isStream(t)?new m(e,t):u.prepareContent(e,t,s.binary,s.optimizedBinaryString,s.base64);var h=new d(e,o,s);this.files[e]=h}var i=e("./utf8"),u=e("./utils"),l=e("./stream/GenericWorker"),aLine truncated
|
||||||
|
,t.exports=i},{"../utils":32,"./Uint8ArrayReader":21}],20:[function(e,t,r){"use strict";var n=e("./DataReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.byteAt=function(e){return this.data.charCodeAt(this.zero+e)},i.prototype.lastIndexOfSignature=function(e){return this.data.lastIndexOf(e)-this.zero},i.prototype.readAndCheckSignature=function(e){return e===this.readData(4)},i.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./DataReader":18}],21:[function(e,t,r){"use strict";var n=e("./ArrayReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.readData=function(e){if(this.checkOffset(e),0===e)return new Uint8Array(0);var t=this.data.subarray(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./ArrayReader":17}],22:[function(e,t,r){"use strict";var n=e("../utils"),i=e("../support"),s=e("./ArrayReader"),a=e("./StringReader"),o=e("./NodeBufferReader"),h=e("./Uint8ArrayReader");t.exports=function(e){var t=n.getTypeOf(e);return n.checkSupport(t),"string"!==t||i.uint8array?"nodebuffer"===t?new o(e):i.uint8array?new h(n.transformTo("uint8array",e)):new s(n.transformTo("array",e)):new a(e)}},{"../support":30,"../utils":32,"./ArrayReader":17,"./NodeBufferReader":19,"./StringReader":20,"./Uint8ArrayReader":21}],23:[function(e,t,r){"use strict";r.LOCAL_FILE_HEADER="PK",r.CENTRAL_FILE_HEADER="PK",r.CENTRAL_DIRECTORY_END="PK",r.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",r.ZIP64_CENTRAL_DIRECTORY_END="PK",r.DATA_DESCRIPTOR="PK\b"},{}],24:[function(e,t,r){"use strict";var n=e("./GenericWorker"),i=e("../utils");function s(e){n.call(this,"ConvertWorker to "+e),this.destType=e}i.inherits(s,n),s.prototype.processChunk=function(e){this.push({data:i.transformTo(this.destType,e.data),meta:e.meta})},t.exports=s},{"../utils":32,"./GenericWorker":28}],25:[function(e,t,r){"use strict";var n=e("./GenericWorker"),i=e("../crc32");function s(){n.call(this,"Crc32Probe"),this.withStreamInfo("crc32",0)}e("../utils").inherits(s,n),s.prototype.processChunk=function(e){this.streamInfo.crc32=i(e.data,this.streamInfo.crc32||0),this.push(e)},t.exports=s},{"../crc32":4,"../utils":32,"./GenericWorker":28}],26:[function(e,t,r){"use strict";var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataLengthProbe for "+e),this.propName=e,this.withStreamInfo(e,0)}n.inherits(s,i),s.prototype.processChunk=function(e){if(e){var t=this.streamInfo[this.propName]||0;this.streamInfo[this.propName]=t+e.data.length}i.prototype.processChunk.call(this,e)},t.exports=s},{"../utils":32,"./GenericWorker":28}],27:[function(e,t,r){"use strict";var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataWorker");var t=this;this.dataIsReady=!1,this.index=0,this.max=0,this.data=null,this.type="",this._tickScheduled=!1,e.then(function(e){t.dataIsReady=!0,t.data=e,t.max=e&&e.length||0,t.type=n.getTypeOf(e),t.isPaused||t._tickAndRepeat()},function(e){t.error(e)})}n.inherits(s,i),s.prototype.cleanUp=function(){i.prototype.cleanUp.call(this),this.data=null},s.prototype.resume=function(){return!!i.prototype.resume.call(this)&&(!this._tickScheduled&&this.dataIsReady&&(this._tickScheduled=!0,n.delay(this._tickAndRepeat,[],this)),!0)},s.prototype._tickAndRepeat=function(){this._tickScheduled=!1,this.isPaused||this.isFinished||(this._tick(),this.isFinished||(n.delay(this._tickAndRepeat,[],this),this._tickScheduled=!0))},s.prototype._tick=function(){if(this.isPaused||this.isFinished)return!1;var e=null,t=Math.min(this.max,this.index+16384);if(this.index>=this.max)return this.end();switch(this.type){case"string":e=this.data.substring(this.index,t);break;case"uint8array":e=this.data.subarray(this.index,t);break;case"array":case"nodebuffer":e=this.data.slice(this.index,t)}return this.index=t,this.push({data:e,meta:{percent:this.max?this.index/this.max*100:0}})},t.exports=s},{"../utils":32,"./GenericWorker":28}],28:[function(e,t,r){"use strict";function n(e){this.name=e||"default",this.streamInfo={},this.generatedError=null,this.extraStreamInfo={},this.isPaused=!0,this.isFinished=!1,this.isLocked=!1,this._listeners={data:[],end:[],error:[]},this.previous=null}n.prototype={push:function(e){this.emit("data",e)},end:function(){if(this.isFinished)return!1;this.flush();try{this.emit("end"),this.cleanUp(),this.isFinished=!0}catch(e){this.emit("error",e)}return!0},error:function(e){return!this.isFinished&&(this.isPaused?this.generatedError=e:(this.isFinished=!0,this.emit("error",e),this.previous&&this.previous.error(e),this.cleanUp()),!0)},on:function(e,t){return this._listeners[e].push(t),this},cleanUp:function(){this.streamInfo=this.generatedError=this.extraStreamInfo=null,this._listeners=[]},emit:function(e,t){if(this._listeners[e])for(var r=0;r<this._listeners[e].length;r++)this._listeners[e][r].call(this,t)},pipe:function(e){return e.Line truncated
|
||||||
|
Array(2*s);for(t=r=0;t<s;)if((n=e[t++])<128)a[r++]=n;else if(4<(i=u[n]))a[r++]=65533,t+=i-1;else{for(n&=2===i?31:3===i?15:7;1<i&&t<s;)n=n<<6|63&e[t++],i--;1<i?a[r++]=65533:n<65536?a[r++]=n:(n-=65536,a[r++]=55296|n>>10&1023,a[r++]=56320|1023&n)}return a.length!==r&&(a.subarray?a=a.subarray(0,r):a.length=r),o.applyFromCharCode(a)}(e=o.transformTo(h.uint8array?"uint8array":"array",e))},o.inherits(a,n),a.prototype.processChunk=function(e){var t=o.transformTo(h.uint8array?"uint8array":"array",e.data);if(this.leftOver&&this.leftOver.length){if(h.uint8array){var r=t;(t=new Uint8Array(r.length+this.leftOver.length)).set(this.leftOver,0),t.set(r,this.leftOver.length)}else t=this.leftOver.concat(t);this.leftOver=null}var n=function(e,t){var r;for((t=t||e.length)>e.length&&(t=e.length),r=t-1;0<=r&&128==(192&e[r]);)r--;return r<0?t:0===r?t:r+u[e[r]]>t?r:t}(t),i=t;n!==t.length&&(h.uint8array?(i=t.subarray(0,n),this.leftOver=t.subarray(n,t.length)):(i=t.slice(0,n),this.leftOver=t.slice(n,t.length))),this.push({data:s.utf8decode(i),meta:e.meta})},a.prototype.flush=function(){this.leftOver&&this.leftOver.length&&(this.push({data:s.utf8decode(this.leftOver),meta:{}}),this.leftOver=null)},s.Utf8DecodeWorker=a,o.inherits(l,n),l.prototype.processChunk=function(e){this.push({data:s.utf8encode(e.data),meta:e.meta})},s.Utf8EncodeWorker=l},{"./nodejsUtils":14,"./stream/GenericWorker":28,"./support":30,"./utils":32}],32:[function(e,t,a){"use strict";var o=e("./support"),h=e("./base64"),r=e("./nodejsUtils"),u=e("./external");function n(e){return e}function l(e,t){for(var r=0;r<e.length;++r)t[r]=255&e.charCodeAt(r);return t}e("setimmediate"),a.newBlob=function(t,r){a.checkSupport("blob");try{return new Blob([t],{type:r})}catch(e){try{var n=new(self.BlobBuilder||self.WebKitBlobBuilder||self.MozBlobBuilder||self.MSBlobBuilder);return n.append(t),n.getBlob(r)}catch(e){throw new Error("Bug : can't construct the Blob.")}}};var i={stringifyByChunk:function(e,t,r){var n=[],i=0,s=e.length;if(s<=r)return String.fromCharCode.apply(null,e);for(;i<s;)"array"===t||"nodebuffer"===t?n.push(String.fromCharCode.apply(null,e.slice(i,Math.min(i+r,s)))):n.push(String.fromCharCode.apply(null,e.subarray(i,Math.min(i+r,s)))),i+=r;return n.join("")},stringifyByChar:function(e){for(var t="",r=0;r<e.length;r++)t+=String.fromCharCode(e[r]);return t},applyCanBeUsed:{uint8array:function(){try{return o.uint8array&&1===String.fromCharCode.apply(null,new Uint8Array(1)).length}catch(e){return!1}}(),nodebuffer:function(){try{return o.nodebuffer&&1===String.fromCharCode.apply(null,r.allocBuffer(1)).length}catch(e){return!1}}()}};function s(e){var t=65536,r=a.getTypeOf(e),n=!0;if("uint8array"===r?n=i.applyCanBeUsed.uint8array:"nodebuffer"===r&&(n=i.applyCanBeUsed.nodebuffer),n)for(;1<t;)try{return i.stringifyByChunk(e,r,t)}catch(e){t=Math.floor(t/2)}return i.stringifyByChar(e)}function f(e,t){for(var r=0;r<e.length;r++)t[r]=e[r];return t}a.applyFromCharCode=s;var c={};c.string={string:n,array:function(e){return l(e,new Array(e.length))},arraybuffer:function(e){return c.string.uint8array(e).buffer},uint8array:function(e){return l(e,new Uint8Array(e.length))},nodebuffer:function(e){return l(e,r.allocBuffer(e.length))}},c.array={string:s,array:n,arraybuffer:function(e){return new Uint8Array(e).buffer},uint8array:function(e){return new Uint8Array(e)},nodebuffer:function(e){return r.newBufferFrom(e)}},c.arraybuffer={string:function(e){return s(new Uint8Array(e))},array:function(e){return f(new Uint8Array(e),new Array(e.byteLength))},arraybuffer:n,uint8array:function(e){return new Uint8Array(e)},nodebuffer:function(e){return r.newBufferFrom(new Uint8Array(e))}},c.uint8array={string:s,array:function(e){return f(e,new Array(e.length))},arraybuffer:function(e){return e.buffer},uint8array:n,nodebuffer:function(e){return r.newBufferFrom(e)}},c.nodebuffer={string:s,array:function(e){return f(e,new Array(e.length))},arraybuffer:function(e){return c.nodebuffer.uint8array(e).buffer},uint8array:function(e){return f(e,new Uint8Array(e.length))},nodebuffer:n},a.transformTo=function(e,t){if(t=t||"",!e)return t;a.checkSupport(e);var r=a.getTypeOf(t);return c[r][e](t)},a.resolve=function(e){for(var t=e.split("/"),r=[],n=0;n<t.length;n++){var i=t[n];"."===i||""===i&&0!==n&&n!==t.length-1||(".."===i?r.pop():r.push(i))}return r.join("/")},a.getTypeOf=function(e){return"string"==typeof e?"string":"[object Array]"===Object.prototype.toString.call(e)?"array":o.nodebuffer&&r.isBuffer(e)?"nodebuffer":o.uint8array&&e instanceof Uint8Array?"uint8array":o.arraybuffer&&e instanceof ArrayBuffer?"arraybuffer":void 0},a.checkSupport=function(e){if(!o[e.toLowerCase()])throw new Error(e+" is not supported by this platform")},a.MAX_VALUE_16BITS=65535,a.MAX_VALUE_32BITS=-1,a.pretty=function(e){var t,r,n="";for(r=0;r<(e||"").length;r++)n+="\\x"+((t=e.charCodeAt(r))<16?"0":"")+t.toString(16).toUpperCase();return n},a.delay=function(e,t,r){setImmediate(function(){e.apply(r||null,t||[])})},a.inherits=functiLine truncated
|
||||||
|
relativeOffsetEndOfZip64CentralDir<0))throw new Error("Corrupted zip: can't find the ZIP64 end of central directory");this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir),this.checkSignature(s.ZIP64_CENTRAL_DIRECTORY_END),this.readBlockZip64EndOfCentral()}var r=this.centralDirOffset+this.centralDirSize;this.zip64&&(r+=20,r+=12+this.zip64EndOfCentralSize);var n=t-r;if(0<n)this.isSignature(t,s.CENTRAL_FILE_HEADER)||(this.reader.zero=n);else if(n<0)throw new Error("Corrupted zip: missing "+Math.abs(n)+" bytes.")},prepareReader:function(e){this.reader=n(e)},load:function(e){this.prepareReader(e),this.readEndOfCentral(),this.readCentralDir(),this.readLocalFiles()}},t.exports=h},{"./reader/readerFor":22,"./signature":23,"./support":30,"./utils":32,"./zipEntry":34}],34:[function(e,t,r){"use strict";var n=e("./reader/readerFor"),s=e("./utils"),i=e("./compressedObject"),a=e("./crc32"),o=e("./utf8"),h=e("./compressions"),u=e("./support");function l(e,t){this.options=e,this.loadOptions=t}l.prototype={isEncrypted:function(){return 1==(1&this.bitFlag)},useUTF8:function(){return 2048==(2048&this.bitFlag)},readLocalPart:function(e){var t,r;if(e.skip(22),this.fileNameLength=e.readInt(2),r=e.readInt(2),this.fileName=e.readData(this.fileNameLength),e.skip(r),-1===this.compressedSize||-1===this.uncompressedSize)throw new Error("Bug or corrupted zip : didn't get enough information from the central directory (compressedSize === -1 || uncompressedSize === -1)");if(null===(t=function(e){for(var t in h)if(Object.prototype.hasOwnProperty.call(h,t)&&h[t].magic===e)return h[t];return null}(this.compressionMethod)))throw new Error("Corrupted zip : compression "+s.pretty(this.compressionMethod)+" unknown (inner file : "+s.transformTo("string",this.fileName)+")");this.decompressed=new i(this.compressedSize,this.uncompressedSize,this.crc32,t,e.readData(this.compressedSize))},readCentralPart:function(e){this.versionMadeBy=e.readInt(2),e.skip(2),this.bitFlag=e.readInt(2),this.compressionMethod=e.readString(2),this.date=e.readDate(),this.crc32=e.readInt(4),this.compressedSize=e.readInt(4),this.uncompressedSize=e.readInt(4);var t=e.readInt(2);if(this.extraFieldsLength=e.readInt(2),this.fileCommentLength=e.readInt(2),this.diskNumberStart=e.readInt(2),this.internalFileAttributes=e.readInt(2),this.externalFileAttributes=e.readInt(4),this.localHeaderOffset=e.readInt(4),this.isEncrypted())throw new Error("Encrypted zip are not supported");e.skip(t),this.readExtraFields(e),this.parseZIP64ExtraField(e),this.fileComment=e.readData(this.fileCommentLength)},processAttributes:function(){this.unixPermissions=null,this.dosPermissions=null;var e=this.versionMadeBy>>8;this.dir=!!(16&this.externalFileAttributes),0==e&&(this.dosPermissions=63&this.externalFileAttributes),3==e&&(this.unixPermissions=this.externalFileAttributes>>16&65535),this.dir||"/"!==this.fileNameStr.slice(-1)||(this.dir=!0)},parseZIP64ExtraField:function(){if(this.extraFields[1]){var e=n(this.extraFields[1].value);this.uncompressedSize===s.MAX_VALUE_32BITS&&(this.uncompressedSize=e.readInt(8)),this.compressedSize===s.MAX_VALUE_32BITS&&(this.compressedSize=e.readInt(8)),this.localHeaderOffset===s.MAX_VALUE_32BITS&&(this.localHeaderOffset=e.readInt(8)),this.diskNumberStart===s.MAX_VALUE_32BITS&&(this.diskNumberStart=e.readInt(4))}},readExtraFields:function(e){var t,r,n,i=e.index+this.extraFieldsLength;for(this.extraFields||(this.extraFields={});e.index+4<i;)t=e.readInt(2),r=e.readInt(2),n=e.readData(r),this.extraFields[t]={id:t,length:r,value:n};e.setIndex(i)},handleUTF8:function(){var e=u.uint8array?"uint8array":"array";if(this.useUTF8())this.fileNameStr=o.utf8decode(this.fileName),this.fileCommentStr=o.utf8decode(this.fileComment);else{var t=this.findExtraFieldUnicodePath();if(null!==t)this.fileNameStr=t;else{var r=s.transformTo(e,this.fileName);this.fileNameStr=this.loadOptions.decodeFileName(r)}var n=this.findExtraFieldUnicodeComment();if(null!==n)this.fileCommentStr=n;else{var i=s.transformTo(e,this.fileComment);this.fileCommentStr=this.loadOptions.decodeFileName(i)}}},findExtraFieldUnicodePath:function(){var e=this.extraFields[28789];if(e){var t=n(e.value);return 1!==t.readInt(1)?null:a(this.fileName)!==t.readInt(4)?null:o.utf8decode(t.readData(e.length-5))}return null},findExtraFieldUnicodeComment:function(){var e=this.extraFields[25461];if(e){var t=n(e.value);return 1!==t.readInt(1)?null:a(this.fileComment)!==t.readInt(4)?null:o.utf8decode(t.readData(e.length-5))}return null}},t.exports=l},{"./compressedObject":2,"./compressions":3,"./crc32":4,"./reader/readerFor":22,"./support":30,"./utf8":31,"./utils":32}],35:[function(e,t,r){"use strict";function n(e,t,r){this.name=e,this.dir=r.dir,this.date=r.date,this.comment=r.comment,this.unixPermissions=r.unixPermissions,this.dosPermissions=r.dosPermissions,this._data=t,this._dataBinary=r.binary,this.options={compression:r.compression,compressionOptions:r.compressionOptions}}var s=e("./stream/StreamHelper"),i=e("./stream/DataWoLine truncated
|
||||||
|
0,l.resolve(o,s))},function(e){i||(i=!0,l.reject(o,e))})}},o.race=function(e){var t=this;if("[object Array]"!==Object.prototype.toString.call(e))return this.reject(new TypeError("must be an array"));var r=e.length,n=!1;if(!r)return this.resolve([]);var i=-1,s=new this(u);for(;++i<r;)a=e[i],t.resolve(a).then(function(e){n||(n=!0,l.resolve(s,e))},function(e){n||(n=!0,l.reject(s,e))});var a;return s}},{immediate:36}],38:[function(e,t,r){"use strict";var n={};(0,e("./lib/utils/common").assign)(n,e("./lib/deflate"),e("./lib/inflate"),e("./lib/zlib/constants")),t.exports=n},{"./lib/deflate":39,"./lib/inflate":40,"./lib/utils/common":41,"./lib/zlib/constants":44}],39:[function(e,t,r){"use strict";var a=e("./zlib/deflate"),o=e("./utils/common"),h=e("./utils/strings"),i=e("./zlib/messages"),s=e("./zlib/zstream"),u=Object.prototype.toString,l=0,f=-1,c=0,d=8;function p(e){if(!(this instanceof p))return new p(e);this.options=o.assign({level:f,method:d,chunkSize:16384,windowBits:15,memLevel:8,strategy:c,to:""},e||{});var t=this.options;t.raw&&0<t.windowBits?t.windowBits=-t.windowBits:t.gzip&&0<t.windowBits&&t.windowBits<16&&(t.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new s,this.strm.avail_out=0;var r=a.deflateInit2(this.strm,t.level,t.method,t.windowBits,t.memLevel,t.strategy);if(r!==l)throw new Error(i[r]);if(t.header&&a.deflateSetHeader(this.strm,t.header),t.dictionary){var n;if(n="string"==typeof t.dictionary?h.string2buf(t.dictionary):"[object ArrayBuffer]"===u.call(t.dictionary)?new Uint8Array(t.dictionary):t.dictionary,(r=a.deflateSetDictionary(this.strm,n))!==l)throw new Error(i[r]);this._dict_set=!0}}function n(e,t){var r=new p(t);if(r.push(e,!0),r.err)throw r.msg||i[r.err];return r.result}p.prototype.push=function(e,t){var r,n,i=this.strm,s=this.options.chunkSize;if(this.ended)return!1;n=t===~~t?t:!0===t?4:0,"string"==typeof e?i.input=h.string2buf(e):"[object ArrayBuffer]"===u.call(e)?i.input=new Uint8Array(e):i.input=e,i.next_in=0,i.avail_in=i.input.length;do{if(0===i.avail_out&&(i.output=new o.Buf8(s),i.next_out=0,i.avail_out=s),1!==(r=a.deflate(i,n))&&r!==l)return this.onEnd(r),!(this.ended=!0);0!==i.avail_out&&(0!==i.avail_in||4!==n&&2!==n)||("string"===this.options.to?this.onData(h.buf2binstring(o.shrinkBuf(i.output,i.next_out))):this.onData(o.shrinkBuf(i.output,i.next_out)))}while((0<i.avail_in||0===i.avail_out)&&1!==r);return 4===n?(r=a.deflateEnd(this.strm),this.onEnd(r),this.ended=!0,r===l):2!==n||(this.onEnd(l),!(i.avail_out=0))},p.prototype.onData=function(e){this.chunks.push(e)},p.prototype.onEnd=function(e){e===l&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=o.flattenChunks(this.chunks)),this.chunks=[],this.err=e,this.msg=this.strm.msg},r.Deflate=p,r.deflate=n,r.deflateRaw=function(e,t){return(t=t||{}).raw=!0,n(e,t)},r.gzip=function(e,t){return(t=t||{}).gzip=!0,n(e,t)}},{"./utils/common":41,"./utils/strings":42,"./zlib/deflate":46,"./zlib/messages":51,"./zlib/zstream":53}],40:[function(e,t,r){"use strict";var c=e("./zlib/inflate"),d=e("./utils/common"),p=e("./utils/strings"),m=e("./zlib/constants"),n=e("./zlib/messages"),i=e("./zlib/zstream"),s=e("./zlib/gzheader"),_=Object.prototype.toString;function a(e){if(!(this instanceof a))return new a(e);this.options=d.assign({chunkSize:16384,windowBits:0,to:""},e||{});var t=this.options;t.raw&&0<=t.windowBits&&t.windowBits<16&&(t.windowBits=-t.windowBits,0===t.windowBits&&(t.windowBits=-15)),!(0<=t.windowBits&&t.windowBits<16)||e&&e.windowBits||(t.windowBits+=32),15<t.windowBits&&t.windowBits<48&&0==(15&t.windowBits)&&(t.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new i,this.strm.avail_out=0;var r=c.inflateInit2(this.strm,t.windowBits);if(r!==m.Z_OK)throw new Error(n[r]);this.header=new s,c.inflateGetHeader(this.strm,this.header)}function o(e,t){var r=new a(t);if(r.push(e,!0),r.err)throw r.msg||n[r.err];return r.result}a.prototype.push=function(e,t){var r,n,i,s,a,o,h=this.strm,u=this.options.chunkSize,l=this.options.dictionary,f=!1;if(this.ended)return!1;n=t===~~t?t:!0===t?m.Z_FINISH:m.Z_NO_FLUSH,"string"==typeof e?h.input=p.binstring2buf(e):"[object ArrayBuffer]"===_.call(e)?h.input=new Uint8Array(e):h.input=e,h.next_in=0,h.avail_in=h.input.length;do{if(0===h.avail_out&&(h.output=new d.Buf8(u),h.next_out=0,h.avail_out=u),(r=c.inflate(h,m.Z_NO_FLUSH))===m.Z_NEED_DICT&&l&&(o="string"==typeof l?p.string2buf(l):"[object ArrayBuffer]"===_.call(l)?new Uint8Array(l):l,r=c.inflateSetDictionary(this.strm,o)),r===m.Z_BUF_ERROR&&!0===f&&(r=m.Z_OK,f=!1),r!==m.Z_STREAM_END&&r!==m.Z_OK)return this.onEnd(r),!(this.ended=!0);h.next_out&&(0!==h.avail_out&&r!==m.Z_STREAM_END&&(0!==h.avail_in||n!==m.Z_FINISH&&n!==m.Z_SYNC_FLUSH)||("string"===this.options.to?(i=p.utf8border(h.output,h.next_out),s=h.next_out-i,a=p.buf2string(h.output,i),h.next_out=s,h.avail_out=u-s,s&&d.arraySet(h.output,h.output,i,s,0),this.onData(a)):this.onData(d.shrinkBuf(h.output,h.next_out)))),0===h.aLine truncated
|
||||||
|
e,0<=e.block_start?e.block_start:-1,e.strstart-e.block_start,t),e.block_start=e.strstart,F(e.strm)}function U(e,t){e.pending_buf[e.pending++]=t}function P(e,t){e.pending_buf[e.pending++]=t>>>8&255,e.pending_buf[e.pending++]=255&t}function L(e,t){var r,n,i=e.max_chain_length,s=e.strstart,a=e.prev_length,o=e.nice_match,h=e.strstart>e.w_size-z?e.strstart-(e.w_size-z):0,u=e.window,l=e.w_mask,f=e.prev,c=e.strstart+S,d=u[s+a-1],p=u[s+a];e.prev_length>=e.good_match&&(i>>=2),o>e.lookahead&&(o=e.lookahead);do{if(u[(r=t)+a]===p&&u[r+a-1]===d&&u[r]===u[s]&&u[++r]===u[s+1]){s+=2,r++;do{}while(u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&s<c);if(n=S-(c-s),s=c-S,a<n){if(e.match_start=t,o<=(a=n))break;d=u[s+a-1],p=u[s+a]}}}while((t=f[t&l])>h&&0!=--i);return a<=e.lookahead?a:e.lookahead}function j(e){var t,r,n,i,s,a,o,h,u,l,f=e.w_size;do{if(i=e.window_size-e.lookahead-e.strstart,e.strstart>=f+(f-z)){for(c.arraySet(e.window,e.window,f,f,0),e.match_start-=f,e.strstart-=f,e.block_start-=f,t=r=e.hash_size;n=e.head[--t],e.head[t]=f<=n?n-f:0,--r;);for(t=r=f;n=e.prev[--t],e.prev[t]=f<=n?n-f:0,--r;);i+=f}if(0===e.strm.avail_in)break;if(a=e.strm,o=e.window,h=e.strstart+e.lookahead,u=i,l=void 0,l=a.avail_in,u<l&&(l=u),r=0===l?0:(a.avail_in-=l,c.arraySet(o,a.input,a.next_in,l,h),1===a.state.wrap?a.adler=d(a.adler,o,l,h):2===a.state.wrap&&(a.adler=p(a.adler,o,l,h)),a.next_in+=l,a.total_in+=l,l),e.lookahead+=r,e.lookahead+e.insert>=x)for(s=e.strstart-e.insert,e.ins_h=e.window[s],e.ins_h=(e.ins_h<<e.hash_shift^e.window[s+1])&e.hash_mask;e.insert&&(e.ins_h=(e.ins_h<<e.hash_shift^e.window[s+x-1])&e.hash_mask,e.prev[s&e.w_mask]=e.head[e.ins_h],e.head[e.ins_h]=s,s++,e.insert--,!(e.lookahead+e.insert<x)););}while(e.lookahead<z&&0!==e.strm.avail_in)}function Z(e,t){for(var r,n;;){if(e.lookahead<z){if(j(e),e.lookahead<z&&t===l)return A;if(0===e.lookahead)break}if(r=0,e.lookahead>=x&&(e.ins_h=(e.ins_h<<e.hash_shift^e.window[e.strstart+x-1])&e.hash_mask,r=e.prev[e.strstart&e.w_mask]=e.head[e.ins_h],e.head[e.ins_h]=e.strstart),0!==r&&e.strstart-r<=e.w_size-z&&(e.match_length=L(e,r)),e.match_length>=x)if(n=u._tr_tally(e,e.strstart-e.match_start,e.match_length-x),e.lookahead-=e.match_length,e.match_length<=e.max_lazy_match&&e.lookahead>=x){for(e.match_length--;e.strstart++,e.ins_h=(e.ins_h<<e.hash_shift^e.window[e.strstart+x-1])&e.hash_mask,r=e.prev[e.strstart&e.w_mask]=e.head[e.ins_h],e.head[e.ins_h]=e.strstart,0!=--e.match_length;);e.strstart++}else e.strstart+=e.match_length,e.match_length=0,e.ins_h=e.window[e.strstart],e.ins_h=(e.ins_h<<e.hash_shift^e.window[e.strstart+1])&e.hash_mask;else n=u._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++;if(n&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=e.strstart<x-1?e.strstart:x-1,t===f?(N(e,!0),0===e.strm.avail_out?O:B):e.last_lit&&(N(e,!1),0===e.strm.avail_out)?A:I}function W(e,t){for(var r,n,i;;){if(e.lookahead<z){if(j(e),e.lookahead<z&&t===l)return A;if(0===e.lookahead)break}if(r=0,e.lookahead>=x&&(e.ins_h=(e.ins_h<<e.hash_shift^e.window[e.strstart+x-1])&e.hash_mask,r=e.prev[e.strstart&e.w_mask]=e.head[e.ins_h],e.head[e.ins_h]=e.strstart),e.prev_length=e.match_length,e.prev_match=e.match_start,e.match_length=x-1,0!==r&&e.prev_length<e.max_lazy_match&&e.strstart-r<=e.w_size-z&&(e.match_length=L(e,r),e.match_length<=5&&(1===e.strategy||e.match_length===x&&4096<e.strstart-e.match_start)&&(e.match_length=x-1)),e.prev_length>=x&&e.match_length<=e.prev_length){for(i=e.strstart+e.lookahead-x,n=u._tr_tally(e,e.strstart-1-e.prev_match,e.prev_length-x),e.lookahead-=e.prev_length-1,e.prev_length-=2;++e.strstart<=i&&(e.ins_h=(e.ins_h<<e.hash_shift^e.window[e.strstart+x-1])&e.hash_mask,r=e.prev[e.strstart&e.w_mask]=e.head[e.ins_h],e.head[e.ins_h]=e.strstart),0!=--e.prev_length;);if(e.match_available=0,e.match_length=x-1,e.strstart++,n&&(N(e,!1),0===e.strm.avail_out))return A}else if(e.match_available){if((n=u._tr_tally(e,0,e.window[e.strstart-1]))&&N(e,!1),e.strstart++,e.lookahead--,0===e.strm.avail_out)return A}else e.match_available=1,e.strstart++,e.lookahead--}return e.match_available&&(n=u._tr_tally(e,0,e.window[e.strstart-1]),e.match_available=0),e.insert=e.strstart<x-1?e.strstart:x-1,t===f?(N(e,!0),0===e.strm.avail_out?O:B):e.last_lit&&(N(e,!1),0===e.strm.avail_out)?A:I}function M(e,t,r,n,i){this.good_length=e,this.max_lazy=t,this.nice_length=r,this.max_chain=n,this.func=i}function H(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=v,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,thisLine truncated
|
||||||
|
i=n.pending,n.pending===n.pending_buf_size)){s=1;break}s=n.gzindex<n.gzhead.comment.length?255&n.gzhead.comment.charCodeAt(n.gzindex++):0,U(n,s)}while(0!==s);n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),0===s&&(n.status=103)}else n.status=103;if(103===n.status&&(n.gzhead.hcrc?(n.pending+2>n.pending_buf_size&&F(e),n.pending+2<=n.pending_buf_size&&(U(n,255&e.adler),U(n,e.adler>>8&255),e.adler=0,n.status=E)):n.status=E),0!==n.pending){if(F(e),0===e.avail_out)return n.last_flush=-1,m}else if(0===e.avail_in&&T(t)<=T(r)&&t!==f)return R(e,-5);if(666===n.status&&0!==e.avail_in)return R(e,-5);if(0!==e.avail_in||0!==n.lookahead||t!==l&&666!==n.status){var o=2===n.strategy?function(e,t){for(var r;;){if(0===e.lookahead&&(j(e),0===e.lookahead)){if(t===l)return A;break}if(e.match_length=0,r=u._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++,r&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):e.last_lit&&(N(e,!1),0===e.strm.avail_out)?A:I}(n,t):3===n.strategy?function(e,t){for(var r,n,i,s,a=e.window;;){if(e.lookahead<=S){if(j(e),e.lookahead<=S&&t===l)return A;if(0===e.lookahead)break}if(e.match_length=0,e.lookahead>=x&&0<e.strstart&&(n=a[i=e.strstart-1])===a[++i]&&n===a[++i]&&n===a[++i]){s=e.strstart+S;do{}while(n===a[++i]&&n===a[++i]&&n===a[++i]&&n===a[++i]&&n===a[++i]&&n===a[++i]&&n===a[++i]&&n===a[++i]&&i<s);e.match_length=S-(s-i),e.match_length>e.lookahead&&(e.match_length=e.lookahead)}if(e.match_length>=x?(r=u._tr_tally(e,1,e.match_length-x),e.lookahead-=e.match_length,e.strstart+=e.match_length,e.match_length=0):(r=u._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++),r&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):e.last_lit&&(N(e,!1),0===e.strm.avail_out)?A:I}(n,t):h[n.level].func(n,t);if(o!==O&&o!==B||(n.status=666),o===A||o===O)return 0===e.avail_out&&(n.last_flush=-1),m;if(o===I&&(1===t?u._tr_align(n):5!==t&&(u._tr_stored_block(n,0,0,!1),3===t&&(D(n.head),0===n.lookahead&&(n.strstart=0,n.block_start=0,n.insert=0))),F(e),0===e.avail_out))return n.last_flush=-1,m}return t!==f?m:n.wrap<=0?1:(2===n.wrap?(U(n,255&e.adler),U(n,e.adler>>8&255),U(n,e.adler>>16&255),U(n,e.adler>>24&255),U(n,255&e.total_in),U(n,e.total_in>>8&255),U(n,e.total_in>>16&255),U(n,e.total_in>>24&255)):(P(n,e.adler>>>16),P(n,65535&e.adler)),F(e),0<n.wrap&&(n.wrap=-n.wrap),0!==n.pending?m:1)},r.deflateEnd=function(e){var t;return e&&e.state?(t=e.state.status)!==C&&69!==t&&73!==t&&91!==t&&103!==t&&t!==E&&666!==t?R(e,_):(e.state=null,t===E?R(e,-3):m):_},r.deflateSetDictionary=function(e,t){var r,n,i,s,a,o,h,u,l=t.length;if(!e||!e.state)return _;if(2===(s=(r=e.state).wrap)||1===s&&r.status!==C||r.lookahead)return _;for(1===s&&(e.adler=d(e.adler,t,l,0)),r.wrap=0,l>=r.w_size&&(0===s&&(D(r.head),r.strstart=0,r.block_start=0,r.insert=0),u=new c.Buf8(r.w_size),c.arraySet(u,t,l-r.w_size,r.w_size,0),t=u,l=r.w_size),a=e.avail_in,o=e.next_in,h=e.input,e.avail_in=l,e.next_in=0,e.input=t,j(r);r.lookahead>=x;){for(n=r.strstart,i=r.lookahead-(x-1);r.ins_h=(r.ins_h<<r.hash_shift^r.window[n+x-1])&r.hash_mask,r.prev[n&r.w_mask]=r.head[r.ins_h],r.head[r.ins_h]=n,n++,--i;);r.strstart=n,r.lookahead=x-1,j(r)}return r.strstart+=r.lookahead,r.block_start=r.strstart,r.insert=r.lookahead,r.lookahead=0,r.match_length=r.prev_length=x-1,r.match_available=0,e.next_in=o,e.input=h,e.avail_in=a,r.wrap=s,m},r.deflateInfo="pako deflate (from Nodeca project)"},{"../utils/common":41,"./adler32":43,"./crc32":45,"./messages":51,"./trees":52}],47:[function(e,t,r){"use strict";t.exports=function(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}},{}],48:[function(e,t,r){"use strict";t.exports=function(e,t){var r,n,i,s,a,o,h,u,l,f,c,d,p,m,_,g,b,v,y,w,k,x,S,z,C;r=e.state,n=e.next_in,z=e.input,i=n+(e.avail_in-5),s=e.next_out,C=e.output,a=s-(t-e.avail_out),o=s+(e.avail_out-257),h=r.dmax,u=r.wsize,l=r.whave,f=r.wnext,c=r.window,d=r.hold,p=r.bits,m=r.lencode,_=r.distcode,g=(1<<r.lenbits)-1,b=(1<<r.distbits)-1;e:do{p<15&&(d+=z[n++]<<p,p+=8,d+=z[n++]<<p,p+=8),v=m[d&g];t:for(;;){if(d>>>=y=v>>>24,p-=y,0===(y=v>>>16&255))C[s++]=65535&v;else{if(!(16&y)){if(0==(64&y)){v=m[(65535&v)+(d&(1<<y)-1)];continue t}if(32&y){r.mode=12;break e}e.msg="invalid literal/length code",r.mode=30;break e}w=65535&v,(y&=15)&&(p<y&&(d+=z[n++]<<p,p+=8),w+=d&(1<<y)-1,d>>>=y,p-=y),p<15&&(d+=z[n++]<<p,p+=8,d+=z[n++]<<p,p+=8),v=_[d&b];r:for(;;){if(d>>>=y=v>>>24,p-=y,!(16&(y=v>>>16&255))){if(0==(64&y)){v=_[(65535&v)+(d&(1<<y)-1)];continue r}e.msg="invalid distance code",r.mode=30;break e}if(k=65535&v,p<(y&=15)&&(d+=z[n++]<<p,(p+=8)<y&&(d+=z[n++]<<p,p+=8)),h<(k+=d&(1<<y)-1)){e.msg="invalid distance too far back",r.mode=30;break e}if(d>>>=y,p-=y,(y=s-a)<k){if(l<(y=k-y)&&r.sane){e.msg="invalid distance too far back",r.mode=30;break e}if(S=c,(x=0)===f){if(x+=u-y,y<w){for(w-=y;C[s++]Line truncated
|
||||||
|
mode=7;case 7:if(2048&r.flags){if(0===o)break e;for(d=0;k=n[s+d++],r.head&&k&&r.length<65536&&(r.head.name+=String.fromCharCode(k)),k&&d<o;);if(512&r.flags&&(r.check=B(r.check,n,d,s)),o-=d,s+=d,k)break e}else r.head&&(r.head.name=null);r.length=0,r.mode=8;case 8:if(4096&r.flags){if(0===o)break e;for(d=0;k=n[s+d++],r.head&&k&&r.length<65536&&(r.head.comment+=String.fromCharCode(k)),k&&d<o;);if(512&r.flags&&(r.check=B(r.check,n,d,s)),o-=d,s+=d,k)break e}else r.head&&(r.head.comment=null);r.mode=9;case 9:if(512&r.flags){for(;l<16;){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}if(u!==(65535&r.check)){e.msg="header crc mismatch",r.mode=30;break}l=u=0}r.head&&(r.head.hcrc=r.flags>>9&1,r.head.done=!0),e.adler=r.check=0,r.mode=12;break;case 10:for(;l<32;){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}e.adler=r.check=L(u),l=u=0,r.mode=11;case 11:if(0===r.havedict)return e.next_out=a,e.avail_out=h,e.next_in=s,e.avail_in=o,r.hold=u,r.bits=l,2;e.adler=r.check=1,r.mode=12;case 12:if(5===t||6===t)break e;case 13:if(r.last){u>>>=7&l,l-=7&l,r.mode=27;break}for(;l<3;){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}switch(r.last=1&u,l-=1,3&(u>>>=1)){case 0:r.mode=14;break;case 1:if(j(r),r.mode=20,6!==t)break;u>>>=2,l-=2;break e;case 2:r.mode=17;break;case 3:e.msg="invalid block type",r.mode=30}u>>>=2,l-=2;break;case 14:for(u>>>=7&l,l-=7&l;l<32;){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}if((65535&u)!=(u>>>16^65535)){e.msg="invalid stored block lengths",r.mode=30;break}if(r.length=65535&u,l=u=0,r.mode=15,6===t)break e;case 15:r.mode=16;case 16:if(d=r.length){if(o<d&&(d=o),h<d&&(d=h),0===d)break e;I.arraySet(i,n,s,d,a),o-=d,s+=d,h-=d,a+=d,r.length-=d;break}r.mode=12;break;case 17:for(;l<14;){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}if(r.nlen=257+(31&u),u>>>=5,l-=5,r.ndist=1+(31&u),u>>>=5,l-=5,r.ncode=4+(15&u),u>>>=4,l-=4,286<r.nlen||30<r.ndist){e.msg="too many length or distance symbols",r.mode=30;break}r.have=0,r.mode=18;case 18:for(;r.have<r.ncode;){for(;l<3;){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}r.lens[A[r.have++]]=7&u,u>>>=3,l-=3}for(;r.have<19;)r.lens[A[r.have++]]=0;if(r.lencode=r.lendyn,r.lenbits=7,S={bits:r.lenbits},x=T(0,r.lens,0,19,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid code lengths set",r.mode=30;break}r.have=0,r.mode=19;case 19:for(;r.have<r.nlen+r.ndist;){for(;g=(C=r.lencode[u&(1<<r.lenbits)-1])>>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}if(b<16)u>>>=_,l-=_,r.lens[r.have++]=b;else{if(16===b){for(z=_+2;l<z;){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}if(u>>>=_,l-=_,0===r.have){e.msg="invalid bit length repeat",r.mode=30;break}k=r.lens[r.have-1],d=3+(3&u),u>>>=2,l-=2}else if(17===b){for(z=_+3;l<z;){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}l-=_,k=0,d=3+(7&(u>>>=_)),u>>>=3,l-=3}else{for(z=_+7;l<z;){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}l-=_,k=0,d=11+(127&(u>>>=_)),u>>>=7,l-=7}if(r.have+d>r.nlen+r.ndist){e.msg="invalid bit length repeat",r.mode=30;break}for(;d--;)r.lens[r.have++]=k}}if(30===r.mode)break;if(0===r.lens[256]){e.msg="invalid code -- missing end-of-block",r.mode=30;break}if(r.lenbits=9,S={bits:r.lenbits},x=T(D,r.lens,0,r.nlen,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid literal/lengths set",r.mode=30;break}if(r.distbits=6,r.distcode=r.distdyn,S={bits:r.distbits},x=T(F,r.lens,r.nlen,r.ndist,r.distcode,0,r.work,S),r.distbits=S.bits,x){e.msg="invalid distances set",r.mode=30;break}if(r.mode=20,6===t)break e;case 20:r.mode=21;case 21:if(6<=o&&258<=h){e.next_out=a,e.avail_out=h,e.next_in=s,e.avail_in=o,r.hold=u,r.bits=l,R(e,c),a=e.next_out,i=e.output,h=e.avail_out,s=e.next_in,n=e.input,o=e.avail_in,u=r.hold,l=r.bits,12===r.mode&&(r.back=-1);break}for(r.back=0;g=(C=r.lencode[u&(1<<r.lenbits)-1])>>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}if(g&&0==(240&g)){for(v=_,y=g,w=b;g=(C=r.lencode[w+((u&(1<<v+y)-1)>>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}u>>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,r.length=b,0===g){r.mode=26;break}if(32&g){r.back=-1,r.mode=12;break}if(64&g){e.msg="invalid literal/length code",r.mode=30;break}r.extra=15&g,r.mode=22;case 22:if(r.extra){for(z=r.extra;l<z;){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}r.length+=u&(1<<r.extra)-1,u>>>=r.extra,l-=r.extra,r.back+=r.extra}r.was=r.length,r.mode=23;case 23:for(;g=(C=r.distcode[u&(1<<r.distbits)-1])>>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}if(0==(240&g)){for(v=_,y=g,w=b;g=(C=r.distcode[w+((u&(1<<v+y)-1)>>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}u>>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,64&g){e.msg="invalid distance code",r.mode=30;break}r.offset=b,r.extra=15&g,r.mode=24;case 24:if(r.extra){for(z=r.extra;l<z;){if(0===o)break e;o--,u+=n[s++]<<l,l+=8}r.offset+=u&(1<<r.extra)-1,u>>>=r.extra,l-=r.extra,r.back+=r.extra}if(r.offset>r.dmax){e.msg="invalid distance too far back",r.mode=30;break}r.mode=25;case 25:if(0===h)break e;if(d=c-h,r.offset>d){if((d=r.offset-d)Line truncated
|
||||||
|
o=e[2*i+1];0!==o&&(e[2*i]=j(s[o]++,o))}}function W(e){var t;for(t=0;t<l;t++)e.dyn_ltree[2*t]=0;for(t=0;t<f;t++)e.dyn_dtree[2*t]=0;for(t=0;t<c;t++)e.bl_tree[2*t]=0;e.dyn_ltree[2*m]=1,e.opt_len=e.static_len=0,e.last_lit=e.matches=0}function M(e){8<e.bi_valid?U(e,e.bi_buf):0<e.bi_valid&&(e.pending_buf[e.pending++]=e.bi_buf),e.bi_buf=0,e.bi_valid=0}function H(e,t,r,n){var i=2*t,s=2*r;return e[i]<e[s]||e[i]===e[s]&&n[t]<=n[r]}function G(e,t,r){for(var n=e.heap[r],i=r<<1;i<=e.heap_len&&(i<e.heap_len&&H(t,e.heap[i+1],e.heap[i],e.depth)&&i++,!H(t,n,e.heap[i],e.depth));)e.heap[r]=e.heap[i],r=i,i<<=1;e.heap[r]=n}function K(e,t,r){var n,i,s,a,o=0;if(0!==e.last_lit)for(;n=e.pending_buf[e.d_buf+2*o]<<8|e.pending_buf[e.d_buf+2*o+1],i=e.pending_buf[e.l_buf+o],o++,0===n?L(e,i,t):(L(e,(s=A[i])+u+1,t),0!==(a=w[s])&&P(e,i-=I[s],a),L(e,s=N(--n),r),0!==(a=k[s])&&P(e,n-=T[s],a)),o<e.last_lit;);L(e,m,t)}function Y(e,t){var r,n,i,s=t.dyn_tree,a=t.stat_desc.static_tree,o=t.stat_desc.has_stree,h=t.stat_desc.elems,u=-1;for(e.heap_len=0,e.heap_max=_,r=0;r<h;r++)0!==s[2*r]?(e.heap[++e.heap_len]=u=r,e.depth[r]=0):s[2*r+1]=0;for(;e.heap_len<2;)s[2*(i=e.heap[++e.heap_len]=u<2?++u:0)]=1,e.depth[i]=0,e.opt_len--,o&&(e.static_len-=a[2*i+1]);for(t.max_code=u,r=e.heap_len>>1;1<=r;r--)G(e,s,r);for(i=h;r=e.heap[1],e.heap[1]=e.heap[e.heap_len--],G(e,s,1),n=e.heap[1],e.heap[--e.heap_max]=r,e.heap[--e.heap_max]=n,s[2*i]=s[2*r]+s[2*n],e.depth[i]=(e.depth[r]>=e.depth[n]?e.depth[r]:e.depth[n])+1,s[2*r+1]=s[2*n+1]=i,e.heap[1]=i++,G(e,s,1),2<=e.heap_len;);e.heap[--e.heap_max]=e.heap[1],function(e,t){var r,n,i,s,a,o,h=t.dyn_tree,u=t.max_code,l=t.stat_desc.static_tree,f=t.stat_desc.has_stree,c=t.stat_desc.extra_bits,d=t.stat_desc.extra_base,p=t.stat_desc.max_length,m=0;for(s=0;s<=g;s++)e.bl_count[s]=0;for(h[2*e.heap[e.heap_max]+1]=0,r=e.heap_max+1;r<_;r++)p<(s=h[2*h[2*(n=e.heap[r])+1]+1]+1)&&(s=p,m++),h[2*n+1]=s,u<n||(e.bl_count[s]++,a=0,d<=n&&(a=c[n-d]),o=h[2*n],e.opt_len+=o*(s+a),f&&(e.static_len+=o*(l[2*n+1]+a)));if(0!==m){do{for(s=p-1;0===e.bl_count[s];)s--;e.bl_count[s]--,e.bl_count[s+1]+=2,e.bl_count[p]--,m-=2}while(0<m);for(s=p;0!==s;s--)for(n=e.bl_count[s];0!==n;)u<(i=e.heap[--r])||(h[2*i+1]!==s&&(e.opt_len+=(s-h[2*i+1])*h[2*i],h[2*i+1]=s),n--)}}(e,t),Z(s,u,e.bl_count)}function X(e,t,r){var n,i,s=-1,a=t[1],o=0,h=7,u=4;for(0===a&&(h=138,u=3),t[2*(r+1)+1]=65535,n=0;n<=r;n++)i=a,a=t[2*(n+1)+1],++o<h&&i===a||(o<u?e.bl_tree[2*i]+=o:0!==i?(i!==s&&e.bl_tree[2*i]++,e.bl_tree[2*b]++):o<=10?e.bl_tree[2*v]++:e.bl_tree[2*y]++,s=i,u=(o=0)===a?(h=138,3):i===a?(h=6,3):(h=7,4))}function V(e,t,r){var n,i,s=-1,a=t[1],o=0,h=7,u=4;for(0===a&&(h=138,u=3),n=0;n<=r;n++)if(i=a,a=t[2*(n+1)+1],!(++o<h&&i===a)){if(o<u)for(;L(e,i,e.bl_tree),0!=--o;);else 0!==i?(i!==s&&(L(e,i,e.bl_tree),o--),L(e,b,e.bl_tree),P(e,o-3,2)):o<=10?(L(e,v,e.bl_tree),P(e,o-3,3)):(L(e,y,e.bl_tree),P(e,o-11,7));s=i,u=(o=0)===a?(h=138,3):i===a?(h=6,3):(h=7,4)}}n(T);var q=!1;function J(e,t,r,n){P(e,(s<<1)+(n?1:0),3),function(e,t,r,n){M(e),n&&(U(e,r),U(e,~r)),i.arraySet(e.pending_buf,e.window,t,r,e.pending),e.pending+=r}(e,t,r,!0)}r._tr_init=function(e){q||(function(){var e,t,r,n,i,s=new Array(g+1);for(n=r=0;n<a-1;n++)for(I[n]=r,e=0;e<1<<w[n];e++)A[r++]=n;for(A[r-1]=n,n=i=0;n<16;n++)for(T[n]=i,e=0;e<1<<k[n];e++)E[i++]=n;for(i>>=7;n<f;n++)for(T[n]=i<<7,e=0;e<1<<k[n]-7;e++)E[256+i++]=n;for(t=0;t<=g;t++)s[t]=0;for(e=0;e<=143;)z[2*e+1]=8,e++,s[8]++;for(;e<=255;)z[2*e+1]=9,e++,s[9]++;for(;e<=279;)z[2*e+1]=7,e++,s[7]++;for(;e<=287;)z[2*e+1]=8,e++,s[8]++;for(Z(z,l+1,s),e=0;e<f;e++)C[2*e+1]=5,C[2*e]=j(e,5);O=new D(z,w,u+1,l,g),B=new D(C,k,0,f,g),R=new D(new Array(0),x,0,c,p)}(),q=!0),e.l_desc=new F(e.dyn_ltree,O),e.d_desc=new F(e.dyn_dtree,B),e.bl_desc=new F(e.bl_tree,R),e.bi_buf=0,e.bi_valid=0,W(e)},r._tr_stored_block=J,r._tr_flush_block=function(e,t,r,n){var i,s,a=0;0<e.level?(2===e.strm.data_type&&(e.strm.data_type=function(e){var t,r=4093624447;for(t=0;t<=31;t++,r>>>=1)if(1&r&&0!==e.dyn_ltree[2*t])return o;if(0!==e.dyn_ltree[18]||0!==e.dyn_ltree[20]||0!==e.dyn_ltree[26])return h;for(t=32;t<u;t++)if(0!==e.dyn_ltree[2*t])return h;return o}(e)),Y(e,e.l_desc),Y(e,e.d_desc),a=function(e){var t;for(X(e,e.dyn_ltree,e.l_desc.max_code),X(e,e.dyn_dtree,e.d_desc.max_code),Y(e,e.bl_desc),t=c-1;3<=t&&0===e.bl_tree[2*S[t]+1];t--);return e.opt_len+=3*(t+1)+5+5+4,t}(e),i=e.opt_len+3+7>>>3,(s=e.static_len+3+7>>>3)<=i&&(i=s)):i=s=r+5,r+4<=i&&-1!==t?J(e,t,r,n):4===e.strategy||s===i?(P(e,2+(n?1:0),3),K(e,z,C)):(P(e,4+(n?1:0),3),function(e,t,r,n){var i;for(P(e,t-257,5),P(e,r-1,5),P(e,n-4,4),i=0;i<n;i++)P(e,e.bl_tree[2*S[i]+1],3);V(e,e.dyn_ltree,t-1),V(e,e.dyn_dtree,r-1)}(e,e.l_desc.max_code+1,e.d_desc.max_code+1,a+1),K(e,e.dyn_ltree,e.dyn_dtree)),W(e),n&&M(e)},r._tr_tally=function(e,t,r){return e.pending_buf[e.d_buf+2*e.last_lit]=t>>>8&255,e.pending_buf[e.d_buf+2*e.last_lit+1]=255&t,e.pending_buf[e.l_buf+e.last_lit]=255&r,e.last_lit++,0===t?e.dyn_ltree[2*r]++:(e.matches++,t--,e.dyn_ltree[2*(A[r]+u+1)]++,e.dyn_dtree[2*N(t)]+Line truncated
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
def detectType(value: str) -> str:
|
|
||||||
val = value.strip()
|
|
||||||
# Boolean check
|
|
||||||
if val.lower() in {'true', 'false'}:
|
|
||||||
return 'Boolean'
|
|
||||||
|
|
||||||
# Int check
|
|
||||||
try:
|
|
||||||
int(val)
|
|
||||||
return 'Int'
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Float check
|
|
||||||
try:
|
|
||||||
float(val)
|
|
||||||
return 'Float'
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Default to String
|
|
||||||
return 'String'
|
|
||||||
|
|
||||||
def typeToCType(valType: str) -> str:
|
|
||||||
if valType == 'Int':
|
|
||||||
return 'int'
|
|
||||||
elif valType == 'Float':
|
|
||||||
return 'float'
|
|
||||||
elif valType == 'Boolean':
|
|
||||||
return 'bool'
|
|
||||||
else:
|
|
||||||
return 'char_t*'
|
|
||||||
|
|
||||||
def stringToCType(value: str) -> str:
|
|
||||||
valType = detectType(value)
|
|
||||||
if valType == 'Int':
|
|
||||||
return str(int(value))
|
|
||||||
elif valType == 'Float':
|
|
||||||
return str(float(value))
|
|
||||||
elif valType == 'Boolean':
|
|
||||||
return 'true' if value.lower() == 'true' else 'false'
|
|
||||||
else:
|
|
||||||
escaped = value.replace('\\', '\\\\').replace('"', '\\"')
|
|
||||||
return f'"{escaped}"'
|
|
||||||
Reference in new issue
Block a user