Skip to content

Commit

Permalink
thanm: -b flag for -x
Browse files Browse the repository at this point in the history
  • Loading branch information
DankRank committed Aug 30, 2023
1 parent e9ebeaf commit 690fa6a
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 26 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ What's new in thtk master
- Support for TH18, TH185, TH19 (full) has been added.
- Support th143/bestshot.anm
- The -u flag can now be used to extract anm files with duplicate filenames.
- Images can now be extracted without adding a border using the -b flag.

#### thanm.old
- Will be removed in the next release.
Expand Down
56 changes: 56 additions & 0 deletions thanm/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,62 @@ format_to_rgba(
return (unsigned char*)out;
}

void
png_read_mem(
image_t *image,
void *data,
size_t len)
{
png_image png = {
.version = PNG_IMAGE_VERSION,
.opaque = NULL
};
png_image_begin_read_from_memory(&png, data, len);
if (PNG_IMAGE_FAILED(png)) {
fprintf(stderr, "%s: error decoding png: %s\n", argv0, png.message);
exit(1);
}
png.format = PNG_FORMAT_RGBA;

image->width = png.width;
image->height = png.height;
image->format = FORMAT_RGBA8888;
image->data = malloc(PNG_IMAGE_SIZE(png));

png_image_finish_read(&png, 0, image->data, 0, 0);
if (PNG_IMAGE_FAILED(png)) {
fprintf(stderr, "%s: error decoding png: %s\n", argv0, png.message);
exit(1);
}
}

void *
png_write_mem(
image_t *image,
size_t *outsize)
{
png_image png;
memset(&png, 0, sizeof(png));
png.version = PNG_IMAGE_VERSION;
png.width = image->width;
png.height = image->height;
png.format = PNG_FORMAT_RGBA;

png_image_write_to_memory(&png, 0, outsize, 0, image->data, 0, 0);
if (PNG_IMAGE_FAILED(png)) {
fprintf(stderr, "%s: error encoding png: %s\n", argv0, png.message);
exit(1);
}
void *out = malloc(*outsize);
png_image_write_to_memory(&png, out, outsize, 0, image->data, 0, 0);
if (PNG_IMAGE_FAILED(png)) {
fprintf(stderr, "%s: error encoding png: %s\n", argv0, png.message);
exit(1);
}

return out;
}

image_t*
png_read(
const char* filename)
Expand Down
11 changes: 11 additions & 0 deletions thanm/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ typedef struct {
format_t format;
} image_t;

void
png_read_mem(
image_t *image,
void *data,
size_t len);

void *
png_write_mem(
image_t *image,
size_t *outsize);

image_t*
png_read(
const char* filename);
Expand Down
18 changes: 13 additions & 5 deletions thanm/thanm.1
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@
.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
.\" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
.\" DAMAGE.
.Dd August 28, 2023
.Dd August 30, 2023
.Dt THANM 1
.Os
.Sh NAME
.Nm thanm
.Nd Touhou sprite archive tool
.Sh SYNOPSIS
.Nm
.Op Fl Vfu
.Op Fl Vfub
.Op Oo Fl l | x | r | c Oc Ar version
.Oo Fl m Ar anmmap Oc Ns Ar ...
.Oo Fl s Ar symbols Oc
Expand All @@ -45,15 +45,15 @@ The following commands are available:
.Bl -tag -width Ds
.It Nm Fl l Ar version Oo Fl fu Oc Oo Fl m Ar anmmap Oc Ns Ar ... Ar archive
Displays a specification of the archive.
.It Nm Fl x Ar version Oo Fl fu Oc Ar archive Op Ar
.It Nm Fl x Ar version Oo Fl fub Oc Ar archive Op Ar
Extracts image files.
If no files are specified, all files are extracted.
.It Nm Fl r Ar version Oo Fl f Oc Ar archive Ar name Ar file
.It Nm Fl r Ar version Oo Fl fb Oc Ar archive Ar name Ar file
Replaces an entry in the archive.
The name can be obtained by the
.Fl l
command.
.It Nm Fl c Ar version Oo Fl f Oc Oo Fl m Ar anmmap Oc Ns Ar ... Oo Fl s Ar symbols Oc Ar archive Ar input
.It Nm Fl c Ar version Oo Fl fb Oc Oo Fl m Ar anmmap Oc Ns Ar ... Oo Fl s Ar symbols Oc Ar archive Ar input
Creates a new archive from a specification obtained by the
.Fl l
command.
Expand Down Expand Up @@ -82,6 +82,14 @@ file.
The
.Fl u
option gives unique filenames to extracted images.
.It b
The
.Fl b
option disables adding/removing a border to images with x/y offset.
For TH19,
.Nm
won't recompress the image unless it needs to add a border.
JPEGs are never recompressed, regardless of the setting.
.El
.Sh EXIT STATUS
The
Expand Down
73 changes: 52 additions & 21 deletions thanm/thanm.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ anmmap_t* g_anmmap = NULL;
unsigned int option_force = 0;
unsigned int option_print_offsets = 0;
unsigned int option_unique_filenames = 0;
unsigned int option_dont_add_offset_border = 0;

/* SPECIAL FORMATS:
* 'o' - offset (for labels)
Expand Down Expand Up @@ -1443,10 +1444,12 @@ util_total_entry_size(
unsigned int height = 0;

if (entry && entry->header->hasdata) {
if (entry->header->x + entry->thtx->w > width)
width = entry->header->x + entry->thtx->w;
if (entry->header->y + entry->thtx->h > height)
height = entry->header->y + entry->thtx->h;
const uint32_t ox = option_dont_add_offset_border ? 0 : entry->header->x;
const uint32_t oy = option_dont_add_offset_border ? 0 : entry->header->y;
if (ox + entry->thtx->w > width)
width = ox + entry->thtx->w;
if (oy + entry->thtx->h > height)
height = oy + entry->thtx->h;
}

*widthptr = width;
Expand Down Expand Up @@ -1498,19 +1501,21 @@ anm_replace(
unsigned int y;

unsigned char* converted_data = format_from_rgba((uint32_t*)image->data, width * height, formats[f]);
const uint32_t ox = option_dont_add_offset_border ? 0 : entry->header->x;
const uint32_t oy = option_dont_add_offset_border ? 0 : entry->header->y;

if (anmfp) {
for (y = entry->header->y; y < entry->header->y + entry->thtx->h; ++y) {
for (y = oy; y < oy + entry->thtx->h; ++y) {
if (!file_seek(anmfp,
offset + entry->header->thtxoffset + sizeof(thtx_header_t) + (y - entry->header->y) * entry->thtx->w * format_Bpp(formats[f])))
offset + entry->header->thtxoffset + sizeof(thtx_header_t) + (y - oy) * entry->thtx->w * format_Bpp(formats[f])))
exit(1);
if (!file_write(anmfp, converted_data + y * width * format_Bpp(formats[f]) + entry->header->x * format_Bpp(formats[f]), entry->thtx->w * format_Bpp(formats[f])))
if (!file_write(anmfp, converted_data + y * width * format_Bpp(formats[f]) + ox * format_Bpp(formats[f]), entry->thtx->w * format_Bpp(formats[f])))
exit(1);
}
} else {
for (y = entry->header->y; y < entry->header->y + entry->thtx->h; ++y) {
memcpy(entry->data + (y - entry->header->y) * entry->thtx->w * format_Bpp(formats[f]),
converted_data + y * width * format_Bpp(formats[f]) + entry->header->x * format_Bpp(formats[f]),
for (y = oy; y < oy + entry->thtx->h; ++y) {
memcpy(entry->data + (y - oy) * entry->thtx->w * format_Bpp(formats[f]),
converted_data + y * width * format_Bpp(formats[f]) + ox * format_Bpp(formats[f]),
entry->thtx->w * format_Bpp(formats[f]));
}
}
Expand All @@ -1526,6 +1531,20 @@ anm_replace(
free(image);
}

static unsigned char *
entry_to_rgba(
anm_entry_t *entry,
int is_png)
{
if (is_png) {
image_t image;
png_read_mem(&image, entry->data, entry->thtx->size);
return image.data;
} else {
return format_to_rgba(entry->data, entry->thtx->w * entry->thtx->h, entry->thtx->format);
}
}

static void
anm_extract(
anm_entry_t* entry,
Expand Down Expand Up @@ -1556,25 +1575,33 @@ anm_extract(

util_makepath(filename);

const uint32_t ox = option_dont_add_offset_border ? 0 : entry->header->x;
const uint32_t oy = option_dont_add_offset_border ? 0 : entry->header->y;
int is_png = 0;

/* NEWHU: 19 */
if (version == 19) {
FILE* stream = fopen(filename, "wb");
if (stream) {
fwrite(entry->thtx->data, 1, entry->thtx->size, stream);
fclose(stream);
if (png_identify(entry->thtx->data, entry->thtx->size) && (ox || oy)) {
is_png = 1;
} else {
FILE* stream = fopen(filename, "wb");
if (stream) {
fwrite(entry->thtx->data, 1, entry->thtx->size, stream);
fclose(stream);
}
return;
}
return;
}

image.data = malloc(image.width * image.height * 4);
/* XXX: Why 0xff? */
memset(image.data, 0xff, image.width* image.height * 4);
for (f = 0; f < sizeof(formats) / sizeof(formats[0]); ++f) {
if (formats[f] == entry->thtx->format) {
unsigned char* temp_data = format_to_rgba(entry->data, entry->thtx->w * entry->thtx->h, entry->thtx->format);
for (y = entry->header->y; y < entry->header->y + entry->thtx->h; ++y) {
memcpy(image.data + y * image.width * 4 + entry->header->x * 4,
temp_data + (y - entry->header->y) * entry->thtx->w * 4,
unsigned char* temp_data = entry_to_rgba(entry, is_png);
for (y = oy; y < oy + entry->thtx->h; ++y) {
memcpy(image.data + y * image.width * 4 + ox * 4,
temp_data + (y - oy) * entry->thtx->w * 4,
entry->thtx->w * 4);
}
free(temp_data);
Expand Down Expand Up @@ -2154,7 +2181,7 @@ print_usage(void)
#else
#define USAGE_LIBPNGFLAGS ""
#endif
printf("Usage: %s [-Vfu] [[-l" USAGE_LIBPNGFLAGS "] VERSION] [-m ANMMAP]... [-s SYMBOLS] ARCHIVE ...\n"
printf("Usage: %s [-Vfub] [[-l" USAGE_LIBPNGFLAGS "] VERSION] [-m ANMMAP]... [-s SYMBOLS] ARCHIVE ...\n"
"Options:\n"
" -l VERSION ARCHIVE list archive\n"
#ifdef HAVE_LIBPNG
Expand All @@ -2167,6 +2194,7 @@ print_usage(void)
" -V display version information and exit\n"
" -f ignore errors when possible\n"
" -u give unique filenames to extracted images\n"
" -b don't add/remove a border to images with x/y offset\n"
" -o add address information for for ANM instructions\n"
"VERSION can be:\n"
" 6, 7, 8, 9, 95, 10, 103, 11, 12, 125, 128, 13, 14, 143, 15, 16, 165, 17, 18, 185 or 19\n"
Expand All @@ -2191,7 +2219,7 @@ main(
#ifdef HAVE_LIBPNG
"x:r:c:s:"
#endif
"Vfu";
"Vfub";
int command = -1;

FILE* in;
Expand Down Expand Up @@ -2254,6 +2282,9 @@ main(
case 'u':
option_unique_filenames = 1;
break;
case 'b':
option_dont_add_offset_border = 1;
break;
case 'o':
if (command == 'c') {
fprintf(stderr, "%s: 'x' option can't be used when creating ANM archive\n", argv0);
Expand Down

0 comments on commit 690fa6a

Please sign in to comment.