From 156880d430f058bf224a20f91cd945951a852af1 Mon Sep 17 00:00:00 2001 From: drewcassidy Date: Fri, 9 Apr 2021 01:33:30 -0700 Subject: [PATCH] Add decode command --- quicktex/cli/__init__.py | 4 ++-- quicktex/cli/decode.py | 42 ++++++++++++++++++++++++++++++++++------ quicktex/dds.py | 27 +++++++++++++------------- quicktex/image_utils.py | 5 +---- 4 files changed, 53 insertions(+), 25 deletions(-) diff --git a/quicktex/cli/__init__.py b/quicktex/cli/__init__.py index ac236ca..95640ad 100644 --- a/quicktex/cli/__init__.py +++ b/quicktex/cli/__init__.py @@ -1,6 +1,6 @@ import click -from encode import encode -from decode import decode +from quicktex.cli.encode import encode +from quicktex.cli.decode import decode @click.group() diff --git a/quicktex/cli/decode.py b/quicktex/cli/decode.py index d31a881..cb77cbe 100644 --- a/quicktex/cli/decode.py +++ b/quicktex/cli/decode.py @@ -1,16 +1,46 @@ import click import io -import os +import os.path +import quicktex.dds as dds from PIL import Image +from pathlib import Path @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('-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.argument('filenames', nargs=-1, type=click.Path(exists=True)) -def decode(flip, remove, output, suffix, filenames): +@click.option('-x', '--extension', + 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""" + + 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: - 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) diff --git a/quicktex/dds.py b/quicktex/dds.py index bb58041..447752c 100644 --- a/quicktex/dds.py +++ b/quicktex/dds.py @@ -5,10 +5,10 @@ import os import struct import typing import quicktex.image_utils -import quicktex.s3tc.bc1 -import quicktex.s3tc.bc3 -import quicktex.s3tc.bc4 -import quicktex.s3tc.bc5 +import quicktex.s3tc.bc1 as bc1 +import quicktex.s3tc.bc3 as bc3 +import quicktex.s3tc.bc4 as bc4 +import quicktex.s3tc.bc5 as bc5 from PIL import Image @@ -22,10 +22,10 @@ class DDSFormat: dds_formats = [ - DDSFormat('BC1', quicktex.s3tc.bc1.BC1Texture, quicktex.s3tc.bc1.BC1Encoder, quicktex.s3tc.bc1.BC1Decoder, 'DXT1'), - DDSFormat('BC3', quicktex.s3tc.bc3.BC3Texture, quicktex.s3tc.bc3.BC3Encoder, quicktex.s3tc.bc3.BC3Decoder, 'DXT5'), - DDSFormat('BC4', quicktex.s3tc.bc4.BC4Texture, quicktex.s3tc.bc4.BC4Encoder, quicktex.s3tc.bc4.BC4Decoder, 'ATI1'), - DDSFormat('BC5', quicktex.s3tc.bc5.BC5Texture, quicktex.s3tc.bc5.BC5Encoder, quicktex.s3tc.bc5.BC5Decoder, 'ATI2'), + DDSFormat('BC1', bc1.BC1Texture, bc1.BC1Encoder, bc1.BC1Decoder, 'DXT1'), + DDSFormat('BC3', bc3.BC3Texture, bc3.BC3Encoder, bc3.BC3Decoder, 'DXT5'), + DDSFormat('BC4', bc4.BC4Texture, bc4.BC4Encoder, bc4.BC4Decoder, 'ATI1'), + DDSFormat('BC5', bc5.BC5Texture, bc5.BC5Encoder, bc5.BC5Decoder, 'ATI2'), ] @@ -194,16 +194,17 @@ def read(path: os.PathLike) -> DDSFile: dds = DDSFile() # READ HEADER - assert struct.unpack(' DDSFile: texture = dds.format.texture(*size) # make a new blocktexture of the current mip size nbytes = file.readinto(texture) - assert nbytes == texture.size, 'Unexpected end of file' + assert nbytes == texture.nbytes, 'Unexpected end of file' dds.textures.append(texture) diff --git a/quicktex/image_utils.py b/quicktex/image_utils.py index 2c18f0c..edc80f0 100644 --- a/quicktex/image_utils.py +++ b/quicktex/image_utils.py @@ -27,11 +27,8 @@ def mip_sizes(dimensions: typing.Tuple[int, int], mip_count: typing.Optional[int for mip in range(mip_count): chain.append(dimensions) - dimensions = tuple([max(dim // 2, 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 + dimensions = tuple([max(dim // 2, 1) for dim in dimensions]) return chain - -