mirror of
https://github.com/drewcassidy/quicktex.git
synced 2024-09-13 06:37:34 +00:00
Add decode command
This commit is contained in:
parent
8b6ea69300
commit
156880d430
@ -1,6 +1,6 @@
|
|||||||
import click
|
import click
|
||||||
from encode import encode
|
from quicktex.cli.encode import encode
|
||||||
from decode import decode
|
from quicktex.cli.decode import decode
|
||||||
|
|
||||||
|
|
||||||
@click.group()
|
@click.group()
|
||||||
|
@ -1,16 +1,46 @@
|
|||||||
import click
|
import click
|
||||||
import io
|
import io
|
||||||
import os
|
import os.path
|
||||||
|
import quicktex.dds as dds
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option('-f', '--flip', type=bool, default=True, show_default=True, help="vertically flip image after converting")
|
@click.option('-f', '--flip', help="vertically flip image after converting")
|
||||||
@click.option('-r', '--remove', help="remove input images after converting")
|
@click.option('-r', '--remove', help="remove input images after converting")
|
||||||
@click.option('-o', '--output', help="output file name. Must only specify one input image.")
|
|
||||||
@click.option('-s', '--suffix', type=str, default='', help="suffix to append to output file(s).")
|
@click.option('-s', '--suffix', type=str, default='', help="suffix to append to output file(s).")
|
||||||
@click.argument('filenames', nargs=-1, type=click.Path(exists=True))
|
@click.option('-x', '--extension',
|
||||||
def decode(flip, remove, output, suffix, filenames):
|
type=str, default='png',
|
||||||
|
help="extension to use for output. ignored if output is a single file. output filetype is deduced from this")
|
||||||
|
@click.option('-o', '--output',
|
||||||
|
type=click.Path(exists=True, readable=True), default='.',
|
||||||
|
help="output file name or directory. If outputting to a file, input filenames must be only a single item.")
|
||||||
|
@click.argument('filenames',
|
||||||
|
nargs=-1,
|
||||||
|
type=click.Path(exists=True, readable=True))
|
||||||
|
def decode(flip, remove, suffix, extension, output, filenames):
|
||||||
"""Decode an input texture file to an image"""
|
"""Decode an input texture file to an image"""
|
||||||
|
|
||||||
|
assert len(filenames) != 0, 'No input files provided.'
|
||||||
|
outpath = Path(output)
|
||||||
|
|
||||||
|
if outpath.is_file():
|
||||||
|
assert len(filenames) == 1, 'Provided an output file with multiple inputs.'
|
||||||
|
|
||||||
|
def make_outpath(p):
|
||||||
|
return outpath
|
||||||
|
else:
|
||||||
|
def make_outpath(p):
|
||||||
|
return outpath / (p.stem + suffix + '.' + extension)
|
||||||
|
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
assert filename.endswith(".dds"), "Incorrect file extension"
|
filepath = Path(filename)
|
||||||
|
outpath = make_outpath(filepath)
|
||||||
|
|
||||||
|
assert filepath.is_file(), f"{filename} is not a file!"
|
||||||
|
assert filepath.suffix == '.dds', f"{filename} is not a DDS file!"
|
||||||
|
|
||||||
|
ddsfile = dds.read(filepath)
|
||||||
|
image = ddsfile.decode()
|
||||||
|
image.save(outpath)
|
||||||
|
@ -5,10 +5,10 @@ import os
|
|||||||
import struct
|
import struct
|
||||||
import typing
|
import typing
|
||||||
import quicktex.image_utils
|
import quicktex.image_utils
|
||||||
import quicktex.s3tc.bc1
|
import quicktex.s3tc.bc1 as bc1
|
||||||
import quicktex.s3tc.bc3
|
import quicktex.s3tc.bc3 as bc3
|
||||||
import quicktex.s3tc.bc4
|
import quicktex.s3tc.bc4 as bc4
|
||||||
import quicktex.s3tc.bc5
|
import quicktex.s3tc.bc5 as bc5
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
@ -22,10 +22,10 @@ class DDSFormat:
|
|||||||
|
|
||||||
|
|
||||||
dds_formats = [
|
dds_formats = [
|
||||||
DDSFormat('BC1', quicktex.s3tc.bc1.BC1Texture, quicktex.s3tc.bc1.BC1Encoder, quicktex.s3tc.bc1.BC1Decoder, 'DXT1'),
|
DDSFormat('BC1', bc1.BC1Texture, bc1.BC1Encoder, bc1.BC1Decoder, 'DXT1'),
|
||||||
DDSFormat('BC3', quicktex.s3tc.bc3.BC3Texture, quicktex.s3tc.bc3.BC3Encoder, quicktex.s3tc.bc3.BC3Decoder, 'DXT5'),
|
DDSFormat('BC3', bc3.BC3Texture, bc3.BC3Encoder, bc3.BC3Decoder, 'DXT5'),
|
||||||
DDSFormat('BC4', quicktex.s3tc.bc4.BC4Texture, quicktex.s3tc.bc4.BC4Encoder, quicktex.s3tc.bc4.BC4Decoder, 'ATI1'),
|
DDSFormat('BC4', bc4.BC4Texture, bc4.BC4Encoder, bc4.BC4Decoder, 'ATI1'),
|
||||||
DDSFormat('BC5', quicktex.s3tc.bc5.BC5Texture, quicktex.s3tc.bc5.BC5Encoder, quicktex.s3tc.bc5.BC5Decoder, 'ATI2'),
|
DDSFormat('BC5', bc5.BC5Texture, bc5.BC5Encoder, bc5.BC5Decoder, 'ATI2'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -194,16 +194,17 @@ def read(path: os.PathLike) -> DDSFile:
|
|||||||
dds = DDSFile()
|
dds = DDSFile()
|
||||||
|
|
||||||
# READ HEADER
|
# READ HEADER
|
||||||
assert struct.unpack('<I', file.read(4)) == DDSFile.header_bytes, "Incorrect DDS header size."
|
header_bytes = struct.unpack('<I', file.read(4))[0]
|
||||||
|
assert header_bytes == DDSFile.header_bytes, "Incorrect DDS header size."
|
||||||
|
|
||||||
dds.flags = DDSFlags(struct.unpack('<I', file.read(4))) # read flags enum
|
dds.flags = DDSFlags(struct.unpack('<I', file.read(4))[0]) # read flags enum
|
||||||
dds.size = struct.unpack('<2I', file.read(8))[::-1] # read dimensions
|
dds.size = struct.unpack('<2I', file.read(8))[::-1] # read dimensions
|
||||||
dds.pitch, dds.depth, dds.mipmap_count = struct.unpack('<3I', file.read(12))
|
dds.pitch, dds.depth, dds.mipmap_count = struct.unpack('<3I', file.read(12))
|
||||||
file.read(44) # skip 44 unused bytes of data
|
file.read(44) # skip 44 unused bytes of data
|
||||||
|
|
||||||
assert struct.unpack('<I', file.read(4)) == 32, "Incorrect pixel format size."
|
assert struct.unpack('<I', file.read(4))[0] == 32, "Incorrect pixel format size."
|
||||||
|
|
||||||
dds.pf_flags = PFFlags(struct.unpack('<I', file.read(4)))
|
dds.pf_flags = PFFlags(struct.unpack('<I', file.read(4))[0])
|
||||||
dds.four_cc = file.read(4).decode()
|
dds.four_cc = file.read(4).decode()
|
||||||
dds.pixel_size, *pixel_bitmasks = struct.unpack('<5I', file.read(20))
|
dds.pixel_size, *pixel_bitmasks = struct.unpack('<5I', file.read(20))
|
||||||
|
|
||||||
@ -235,7 +236,7 @@ def read(path: os.PathLike) -> DDSFile:
|
|||||||
texture = dds.format.texture(*size) # make a new blocktexture of the current mip size
|
texture = dds.format.texture(*size) # make a new blocktexture of the current mip size
|
||||||
nbytes = file.readinto(texture)
|
nbytes = file.readinto(texture)
|
||||||
|
|
||||||
assert nbytes == texture.size, 'Unexpected end of file'
|
assert nbytes == texture.nbytes, 'Unexpected end of file'
|
||||||
|
|
||||||
dds.textures.append(texture)
|
dds.textures.append(texture)
|
||||||
|
|
||||||
|
@ -27,11 +27,8 @@ def mip_sizes(dimensions: typing.Tuple[int, int], mip_count: typing.Optional[int
|
|||||||
|
|
||||||
for mip in range(mip_count):
|
for mip in range(mip_count):
|
||||||
chain.append(dimensions)
|
chain.append(dimensions)
|
||||||
dimensions = tuple([max(dim // 2, 1) for dim in dimensions])
|
|
||||||
|
|
||||||
if all([dim == 1 for dim in dimensions]):
|
if all([dim == 1 for dim in dimensions]):
|
||||||
break # we've reached a 1x1 mip and can get no smaller
|
break # we've reached a 1x1 mip and can get no smaller
|
||||||
|
dimensions = tuple([max(dim // 2, 1) for dim in dimensions])
|
||||||
|
|
||||||
return chain
|
return chain
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user