[Scummvm-git-logs] scummvm-tools master -> a5bab4d71a05b73c8cf66f2bc0394548ce0a1ac3
sev-
noreply at scummvm.org
Mon Oct 24 19:20:57 UTC 2022
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm-tools' repo located at https://github.com/scummvm/scummvm-tools .
Summary:
a5bab4d71a HADESCH: Add new tool for decoding hadesch image files
Commit: a5bab4d71a05b73c8cf66f2bc0394548ce0a1ac3
https://github.com/scummvm/scummvm-tools/commit/a5bab4d71a05b73c8cf66f2bc0394548ce0a1ac3
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-10-24T21:20:55+02:00
Commit Message:
HADESCH: Add new tool for decoding hadesch image files
Changed paths:
A engines/hadesch/extract_hadesch_img.cpp
Makefile.common
diff --git a/Makefile.common b/Makefile.common
index f8970a0c..bf8dba30 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -37,6 +37,7 @@ PROGRAMS = \
msn_convert_mod \
scummvm-tools-cli \
extract_hadesch \
+ extract_hadesch_img \
extract_lokalizator \
grim_animb2txt \
grim_bm2bmp \
@@ -149,6 +150,10 @@ extract_hadesch_OBJS := \
engines/hadesch/extract_hadesch.o \
$(UTILS)
+extract_hadesch_img_OBJS := \
+ engines/hadesch/extract_hadesch_img.o \
+ $(UTILS)
+
extract_lokalizator_OBJS := \
engines/scumm/extract_lokalizator.o
diff --git a/engines/hadesch/extract_hadesch_img.cpp b/engines/hadesch/extract_hadesch_img.cpp
new file mode 100644
index 00000000..26b3348a
--- /dev/null
+++ b/engines/hadesch/extract_hadesch_img.cpp
@@ -0,0 +1,303 @@
+/* ScummVM Tools
+ *
+ * ScummVM Tools is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/endian.h"
+#include "common/array.h"
+#include "common/str.h"
+#include "common/util.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+struct palette_element {
+ int idx;
+ int r, g, b;
+ palette_element() = default;
+ palette_element(int idx_in, int r_in, int g_in, int b_in) : idx(idx_in), r(r_in), g(g_in), b(b_in) {}
+};
+
+struct image {
+ int w;
+ int h;
+ int alignw;
+
+ unsigned char *buf;
+
+ ~image() {
+ free(buf);
+ }
+};
+
+int decode_image (const unsigned char *buf, int sz, image* iout) {
+ if (memcmp (buf, "CEL ", 4) != 0) {
+ fprintf (stderr, "Bad signature\n");
+ return 1;
+ }
+
+ int cur;
+ int ssz;
+
+ const unsigned char *dataptr = NULL;
+ int datasize = 0;
+
+ for (cur = 8; cur < sz; cur +=ssz) {
+ const unsigned char *ptr = buf + cur;
+ ssz = READ_BE_UINT32(ptr + 4);
+
+ if (memcmp (ptr, "INFO", 4) == 0) {
+ iout->w = READ_BE_UINT32(ptr + 0x1c);
+ iout->h = READ_BE_UINT32(ptr + 0x20);
+ printf ("Dimensions: %d x %d\n", iout->w, iout->h);
+ printf ("Off: %d x %d\n", -READ_BE_UINT32(ptr + 0x14), -READ_BE_UINT32(ptr + 0x18));
+
+ continue;
+ }
+
+ if (memcmp (ptr, "DATA", 4) == 0) {
+ dataptr = ptr + 8;
+ datasize = ssz - 8;
+ continue;
+ }
+
+ if (memcmp (ptr, "BLTM", 4) == 0
+ || memcmp (ptr, "LINZ", 4) == 0) {
+ continue;
+ }
+
+ fprintf (stderr, "Unknown section: %s\n", ptr);
+ }
+
+
+ iout->alignw = iout->w;
+ if (iout->w % 4)
+ iout->alignw += 4 - (iout->w % 4);
+
+ iout->buf = (unsigned char *) malloc(iout->alignw * iout->h);
+ memset(iout->buf, 0, iout->alignw * iout->h);
+ int line = iout->h-1;
+ int linerem = iout->w;
+
+ unsigned char *outptr = iout->buf + line * iout->alignw;
+
+ for (int i = 0; i < datasize && line >= 0;) {
+ if (dataptr[i] != 0) {
+ int len = MIN(static_cast<int>(dataptr[i]), linerem);
+ memset (outptr, dataptr[i + 1], len);
+ outptr += len;
+ linerem -= dataptr[i];
+ i += 2;
+ continue;
+ }
+
+ if (dataptr[i + 1] != 0) {
+ int len = MIN(static_cast<int>(dataptr[i + 1]), linerem);
+ memcpy(outptr, dataptr + i + 2, len);
+ outptr += len;
+ linerem -= dataptr[i+1];
+ i += 2 + dataptr[i+1];
+ continue;
+ }
+
+ // End of line
+ line--;
+ outptr = iout->buf + line * iout->alignw;
+ linerem = iout->w;
+ i += 2;
+ }
+
+ return 0;
+}
+
+void write_bmp(const Common::Array<palette_element>& palette, const image& img, FILE *fout) {
+ fwrite("BM", 2, 1, fout);
+ unsigned char outbuf[256];
+ unsigned char bmppal[256][4];
+ const int numcols = 256;
+ const int infohdrsize = 40;
+
+ memset(outbuf, 0, sizeof(outbuf));
+ WRITE_LE_UINT32(outbuf, 14 + infohdrsize + numcols * 4 + img.alignw * img.h);
+ WRITE_LE_UINT32(outbuf + 8, 14 + infohdrsize + numcols * 4);
+ WRITE_LE_UINT32(outbuf + 12, infohdrsize);
+ WRITE_LE_UINT32(outbuf + 16, img.w);
+ WRITE_LE_UINT32(outbuf + 20, img.h);
+ WRITE_LE_UINT16(outbuf + 24, 1); // planes
+ WRITE_LE_UINT16(outbuf + 26, 8); // bpp
+ WRITE_LE_UINT32(outbuf + 44, numcols);
+
+ fwrite(outbuf, infohdrsize + 12, 1, fout);
+
+ memset(bmppal, 0, sizeof(bmppal));
+ for (Common::Array<palette_element>::const_iterator it = palette.begin(); it != palette.end(); it++)
+ {
+ bmppal[it->idx][0] = it->b;
+ bmppal[it->idx][1] = it->g;
+ bmppal[it->idx][2] = it->r;
+ }
+
+ fwrite(bmppal, 4 * numcols, 1, fout);
+
+ fwrite(img.buf, img.alignw * img.h, 1, fout);
+}
+
+int main (int argc, char **argv) {
+ unsigned char * buf;
+ size_t sz;
+ FILE *fin;
+
+ if (argc < 3) {
+ fprintf (stderr, "USAGE: %s INFILE OUTDIR\n", argv[0]);
+ return -1;
+ }
+
+ fin = fopen (argv[1], "rb");
+ if (fin == NULL) {
+ fprintf (stderr, "Unable to open %s: %s\n", argv[1], strerror(errno));
+ return -2;
+ }
+ fseek (fin, 0, SEEK_END);
+ sz = ftell (fin);
+ fseek (fin, 0, SEEK_SET);
+
+ buf = (unsigned char *) malloc (sz);
+
+ fread (buf, 1, sz, fin);
+ fclose (fin);
+
+ if (memcmp (buf, "Pod\0file\0\0\0\0", 12) != 0
+ && memcmp (buf, "Pod File\0\0\0\0", 12) != 0
+ && memcmp (buf, "Pod\0\0\0\0\0\0\0\0\0", 12) != 0) {
+ fprintf (stderr, "Bad signature\n");
+ return 1;
+ }
+
+ int filecnt = READ_LE_UINT32(buf + 12);
+
+ FILE *fout;
+
+ int cur = filecnt * 16 + 16;
+ int ctr = 0;
+
+ fprintf (stderr, "%d files\n", filecnt);
+
+ struct file_descriptor {
+ Common::String name;
+ int offset;
+ int size;
+
+ file_descriptor(Common::String nm, int off, int sz) : name(nm), offset(off), size(sz) {}
+ file_descriptor() = default;
+ };
+
+ Common::Array<file_descriptor> images;
+ bool palette_found = false;
+ file_descriptor palette;
+
+ images.reserve(filecnt);
+
+ static const char *kPaletteName = "0";
+
+ for (ctr = 0; ctr < filecnt; ctr++) {
+ unsigned char * headptr = buf + 16 + 16 * ctr;
+ char c = headptr[12];
+ headptr[12] = 0;
+ Common::String name = (const char *) headptr;
+ headptr[12] = c;
+ int csz = READ_LE_UINT32(headptr+12);
+ if (name == kPaletteName) {
+ palette = file_descriptor(name, cur, csz);
+ palette_found = true;
+ } else
+ images.push_back(file_descriptor(name, cur, csz));
+ cur += csz;
+ }
+
+ // Read palette
+ if (!palette_found) {
+ fprintf (stderr, "Couldn't find palette file\n");
+ return 1;
+ }
+
+ const unsigned char *palette_ptr = buf + palette.offset;
+ int palette_size = palette.size;
+ const unsigned char *palette_block_ptr = NULL;
+ int palette_block_size = 0;
+ int ssz = 0;
+
+ if (palette_size < 12) {
+ fprintf (stderr, "Palette file is too short\n");
+ return 1;
+ }
+
+ if (memcmp (palette_ptr, "CEL ", 4) != 0) {
+ fprintf (stderr, "Bad palette signature\n");
+ return 1;
+ }
+
+ for (cur = 8; cur < palette_size; cur += ssz) {
+ const unsigned char *ptr = palette_ptr + cur;
+ ssz = READ_BE_UINT32(ptr + 4);
+
+ if (memcmp (ptr, "PAL ", 4) == 0) {
+ palette_block_ptr = ptr + 8;
+ palette_block_size = ssz - 8;
+ continue;
+ }
+
+ fprintf (stderr, "Unknown palette section: %s\n", ptr);
+ }
+
+ if (palette_block_ptr == NULL) {
+ fprintf (stderr, "Palette file is missing palette section\n");
+ return 1;
+ }
+
+ Common::Array<palette_element> parsed_palette;
+
+ parsed_palette.reserve(palette_block_size / 4);
+
+ for (int i = 0; i < palette_block_size / 4; i++)
+ {
+ const unsigned char *col = palette_block_ptr + 4 * i;
+ parsed_palette.push_back(palette_element(col[0], col[1], col[2], col[3]));
+ }
+
+ for (Common::Array<file_descriptor>::const_iterator it = images.begin();
+ it != images.end(); it++) {
+ image img;
+ printf ("Frame %s\n", it->name.c_str());
+ Common::String fn = Common::String::format("%s/%s.bmp", argv[2], it->name.c_str());
+ fout = fopen(fn.c_str(), "wb");
+ if (fout == NULL) {
+ fprintf (stderr, "Unable to open %s: %s\n", fn.c_str(), strerror(errno));
+ return -3;
+ }
+ if (decode_image(buf + it->offset, it->size, &img)) {
+ fclose(fout);
+ return 1;
+ }
+ write_bmp(parsed_palette, img, fout);
+ fclose(fout);
+ }
+
+ return 0;
+}
More information about the Scummvm-git-logs
mailing list