Repository navigation
Usage
SLTextureDecoder 0.x.y
Decodes Second Life / Firestorm JPEG 2000 texture caches into PNG.
Usage:
SLTextureDecoder --cache-dir <dir> [options]
Options:
--cache-dir <dir> texture cache directory to read (required)
--out-dir <dir> where the PNG files go (default: <cache-dir>/png)
--id <uuid> decode one texture instead of the whole cache
--index <n> decode only the record at this index
--limit <n> stop after n textures
--complete-only skip records whose cached codestream is truncated
--overwrite write over existing PNG files
-v, --verbose log every record
-h, --help show this help
-V, --version show version and linked libraries
Output:
<uuid>.png decoded from a complete codestream
<uuid>.partial.png best effort result from a truncated codestream
Run the tool without any argument to print the same text (and exit with code 1,
because the invocation is incomplete). --help exits with 0.
| Invocation | Selection |
|---|---|
--cache-dir <dir> |
every record that has a body file (mBodySize > 0) |
--cache-dir <dir> --complete-only |
only the records whose codestream is complete on disk |
--limit <n> |
the first n of that selection, in cache index order |
--index <n> |
exactly the record n, whatever --limit/--complete-only say |
--id <uuid> |
the record with that texture id (looked up in texture.entries) |
-
--indexwins over--idwhen both are given. - The next run skips a texture whose PNG is already in the output directory
(that is what makes resuming an interrupted run cheap);
--overwriterewrites it. The name that is checked is the one the record would produce, i.e.<uuid>.partial.pngfor a truncated record,<uuid>.pngotherwise. - A record without a body file (
mBodySize <= 0, a free slot) is counted as failed and reported - it cannot be decoded by definition. - The output directory is created on demand, including
<cacheDir>/pngwhen--out-diris omitted.
<uuid>.png the whole codestream was on disk and decoded losslessly
<uuid>.partial.png only the cached prefix existed; OpenJPEG recovered a blurry
but usable image (best effort, not the original texture)
Two files for the same texture can never appear at once, so the suffix is a reliable "this output is not the real thing" marker for scripts.
The numeric exit code is the error category, so a script can react without
parsing the log (src/utils/Errors.h):
| Code | Name | Typical cause |
|---|---|---|
| 0 | Ok | every selected texture was written (best effort results count as written) |
| 1 | Usage | bad command line, missing --cache-dir, unknown option |
| 2 | CacheNotFound |
--cache-dir is not a directory, or texture.entries / texture.cache is missing |
| 3 | EntryNotFound |
--id is not in the cache, --index out of range, body file missing |
| 4 | CacheTooSmall | header block or texture.cache shorter than the record announces |
| 5 | SizeMismatch | body file size differs from mBodySize
|
| 6 | DecodeError | at least one selected texture could not be decoded even leniently, or a codestream is inconsistent |
| 7 | WriteError | output directory/file could not be created or written |
| 8 | IoError | read failed, short read, file vanished |
| 9 | InvalidFormat |
texture.entries is not a plausible cache (too small, truncated, absurd count) |
Exit code 0 with a non-zero written count is the normal case for a cache full
of truncated records: the tool reports them as best effort instead of failing.
Plain lines on stdout/stderr, no colour codes, so redirecting works:
[INFO] cache D:\FS Cache\texturecache: 196700 records, encoder KDU v8.4.1
[INFO] 120 texture(s) to decode into D:\textures
[INFO] 250/54825 written
[WARN] record 123386: texture has 5 components, dropping the surplus plane
[INFO] done: 120 PNG written (83 best effort), 0 skipped, 0 failed
| Level | When |
|---|---|
INFO |
cache opened, selection, every 250 written PNGs, the final summary |
WARN |
a texture decoded with a caveat (5 components, lenient recovery) |
ERROR |
a record failed; the run continues |
verbose (-v) |
one line per record: index, uuid, file name, size, components, OpenJPEG diagnostics |
# the whole cache, default output <cache-dir>\png, skip what exists
SLTextureDecoder --cache-dir "$env:APPDATA\Firestorm_x64\texturecache"
# a quick smoke test: five records, each one logged
SLTextureDecoder --cache-dir "D:\FS Cache\texturecache" --out-dir D:\textures --limit 5 -v
# only losslessly recoverable textures, into a separate tree
SLTextureDecoder --cache-dir "D:\FS Cache\texturecache" --out-dir D:\textures\complete --complete-only
# one texture you know the id of
SLTextureDecoder --cache-dir "D:\FS Cache\texturecache" --id 8f7d1b1e-0a1b-4c5d-8e9f-0123456789ab
# record 123386 by index
SLTextureDecoder --cache-dir "D:\FS Cache\texturecache" --out-dir D:\one --index 123386 -v
# scripted, quiet: only failures matter
SLTextureDecoder --cache-dir "D:\FS Cache\texturecache" 2> errors.log
if ($LASTEXITCODE -ne 0) { Write-Host "see errors.log" }SLTextureDecoderGUI.exe accepts the same options plus:
--jobs <n> worker threads (0 = one per logical CPU)
--batch convert without opening a window
# the whole cache on four threads, unattended, log to a file
SLTextureDecoderGUI.exe --batch --jobs 4 --cache-dir "D:\FS Cache\texturecache" `
--out-dir D:\textures > run.logSee GUI for the window and Performance for what
--jobs buys you.
MIT licensed - the licence covers the source code only, never the decoded textures. Educational and research use only; not affiliated with Linden Research, Inc. or the Phoenix Firestorm Project - see the Legal notice.
SLTextureDecoder