Mercurial > hg > dmlib
comparison tools/libgfx.c @ 2053:6dfbe976d740
Implement basic initial support for IFF ACBM format images.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 03 Dec 2018 23:05:58 +0200 |
parents | 416af5a842ec |
children | 1a032298adb8 |
comparison
equal
deleted
inserted
replaced
2052:aa8df4f1b785 | 2053:6dfbe976d740 |
---|---|
1452 #define IFF_ID_PBM 0x50424D20 // "PBM " | 1452 #define IFF_ID_PBM 0x50424D20 // "PBM " |
1453 #define IFF_ID_BMHD 0x424D4844 // "BMHD" | 1453 #define IFF_ID_BMHD 0x424D4844 // "BMHD" |
1454 #define IFF_ID_CMAP 0x434D4150 // "CMAP" | 1454 #define IFF_ID_CMAP 0x434D4150 // "CMAP" |
1455 #define IFF_ID_BODY 0x424F4459 // "BODY" | 1455 #define IFF_ID_BODY 0x424F4459 // "BODY" |
1456 #define IFF_ID_CAMG 0x43414D47 // "CAMG" | 1456 #define IFF_ID_CAMG 0x43414D47 // "CAMG" |
1457 #define IFF_ID_ACBM 0x4143424D // "ACBM" | |
1458 #define IFF_ID_ABIT 0x41424954 // "ABIT" | |
1457 | 1459 |
1458 #define IFF_MASK_NONE 0 | 1460 #define IFF_MASK_NONE 0 |
1459 #define IFF_MASK_HAS_MASK 1 | 1461 #define IFF_MASK_HAS_MASK 1 |
1460 #define IFF_MASK_TRANSP 2 | 1462 #define IFF_MASK_TRANSP 2 |
1461 #define IFF_MASK_LASSO 3 | 1463 #define IFF_MASK_LASSO 3 |
1497 DMIFFBMHD bmhd; | 1499 DMIFFBMHD bmhd; |
1498 BOOL planar; | 1500 BOOL planar; |
1499 Uint32 camg; | 1501 Uint32 camg; |
1500 int ncolors; | 1502 int ncolors; |
1501 DMColor *pal; | 1503 DMColor *pal; |
1504 Uint32 idsig; | |
1502 } DMIFF; | 1505 } DMIFF; |
1503 | 1506 |
1504 | 1507 |
1505 static int fmtProbeIFF(const Uint8 *buf, const size_t len) | 1508 static int fmtProbeIFF(const Uint8 *buf, const size_t len) |
1506 { | 1509 { |
1575 | 1578 |
1576 return DMERR_OK; | 1579 return DMERR_OK; |
1577 } | 1580 } |
1578 | 1581 |
1579 | 1582 |
1580 static int dmCheckIFFChunk(DMIFFChunk *dest, DMIFFChunk *chunk, | 1583 static int dmCheckIFFChunk(DMIFFChunk *dest, const DMIFFChunk *chunk, |
1581 const BOOL multi, const Uint32 minSize) | 1584 const BOOL multi, const Uint32 minSize) |
1582 { | 1585 { |
1583 if (dest->count > 0 && !multi) | 1586 if (dest->count > 0 && !multi) |
1584 { | 1587 { |
1585 return dmError(DMERR_INVALID_DATA, | 1588 return dmError(DMERR_INVALID_DATA, |
1662 Uint8 *buf = NULL; | 1665 Uint8 *buf = NULL; |
1663 size_t bufLen = 0; | 1666 size_t bufLen = 0; |
1664 int res = DMERR_OK; | 1667 int res = DMERR_OK; |
1665 const int nplanes = iff->bmhd.nplanes; | 1668 const int nplanes = iff->bmhd.nplanes; |
1666 | 1669 |
1667 if (iff->planar) | 1670 if (iff->idsig == IFF_ID_ILBM) |
1668 { | 1671 { |
1669 // Allocate planar decoding buffer | |
1670 bufLen = ((img->width + 15) / 16) * 2; | 1672 bufLen = ((img->width + 15) / 16) * 2; |
1671 if ((buf = dmMalloc(bufLen)) == NULL) | |
1672 return DMERR_MALLOC; | |
1673 | |
1674 dmMsg(2, "IFF: Line / plane row size %d bytes.\n", bufLen); | 1673 dmMsg(2, "IFF: Line / plane row size %d bytes.\n", bufLen); |
1675 } | 1674 |
1675 } | |
1676 else | |
1677 if (iff->idsig == IFF_ID_ACBM) | |
1678 { | |
1679 bufLen = (img->width * img->height) / 8; | |
1680 dmMsg(2, "IFF: Plane buffer size %d bytes.\n", bufLen); | |
1681 } | |
1682 | |
1683 if (bufLen > 0 && (buf = dmMalloc(bufLen)) == NULL) | |
1684 return DMERR_MALLOC; | |
1676 | 1685 |
1677 // Decode the chunk | 1686 // Decode the chunk |
1687 if (iff->idsig == IFF_ID_ACBM) | |
1688 { | |
1689 for (int plane = 0; plane < nplanes; plane++) | |
1690 { | |
1691 if (!dmf_read_str(fp, buf, bufLen)) | |
1692 { | |
1693 res = dmError(DMERR_FREAD, | |
1694 "IFF: Error in reading image plane #%d.\n", | |
1695 plane); | |
1696 goto out; | |
1697 } | |
1698 | |
1699 for (int yc = 0; yc < img->height; yc++) | |
1700 { | |
1701 Uint8 *dp = img->data + (yc * img->pitch); | |
1702 for (int xc = 0; xc < img->width; xc++) | |
1703 { | |
1704 const Uint8 data = dmDecodeBit(buf + yc * 40, xc); | |
1705 if (data) | |
1706 dp[xc] |= 1 << plane; | |
1707 } | |
1708 } | |
1709 } | |
1710 } | |
1711 else | |
1678 for (int yc = 0; yc < img->height; yc++) | 1712 for (int yc = 0; yc < img->height; yc++) |
1679 { | 1713 { |
1680 Uint8 *dp = img->data + (yc * img->pitch); | 1714 Uint8 *dp = img->data + (yc * img->pitch); |
1681 | 1715 |
1682 if (iff->planar) | 1716 if (iff->idsig == IFF_ID_ILBM) |
1683 { | 1717 { |
1684 // Clear planar decoding buffer | 1718 // Clear planar decoding buffer |
1685 dmMemset(dp, 0, img->pitch); | 1719 dmMemset(dp, 0, img->pitch); |
1686 | 1720 |
1687 for (int plane = 0; plane < nplanes; plane++) | 1721 for (int plane = 0; plane < nplanes; plane++) |
1721 dp[xc] = img->ctransp < 0 ? 0 : img->ctransp; | 1755 dp[xc] = img->ctransp < 0 ? 0 : img->ctransp; |
1722 } | 1756 } |
1723 } | 1757 } |
1724 } | 1758 } |
1725 else | 1759 else |
1760 if (iff->idsig == IFF_ID_PBM) | |
1726 { | 1761 { |
1727 if (!dmIFFReadOneRow(fp, iff, dp, img->width)) | 1762 if (!dmIFFReadOneRow(fp, iff, dp, img->width)) |
1728 { | 1763 { |
1729 res = dmError(DMERR_FREAD, | 1764 res = dmError(DMERR_FREAD, |
1730 "IFF: Error reading PBM image row #%d.\n", yc); | 1765 "IFF: Error reading PBM image row #%d.\n", yc); |
1741 | 1776 |
1742 int dmReadIFFImage(DMResource *fp, DMImage **pimg) | 1777 int dmReadIFFImage(DMResource *fp, DMImage **pimg) |
1743 { | 1778 { |
1744 DMIFFChunk chunk; | 1779 DMIFFChunk chunk; |
1745 DMIFF iff; | 1780 DMIFF iff; |
1746 Uint32 idsig; | |
1747 BOOL parsed = FALSE; | 1781 BOOL parsed = FALSE; |
1748 int res = DMERR_OK; | 1782 int res = DMERR_OK; |
1749 | 1783 |
1750 dmMemset(&iff, 0, sizeof(iff)); | 1784 dmMemset(&iff, 0, sizeof(iff)); |
1751 | 1785 |
1759 "IFF: Not a IFF file (%08X vs %08X / %d).\n", | 1793 "IFF: Not a IFF file (%08X vs %08X / %d).\n", |
1760 chunk.id, IFF_ID_FORM, chunk.size); | 1794 chunk.id, IFF_ID_FORM, chunk.size); |
1761 } | 1795 } |
1762 | 1796 |
1763 // Check IFF ILBM/PBM signature | 1797 // Check IFF ILBM/PBM signature |
1764 if (!dmf_read_be32(fp, &idsig) || | 1798 if (!dmf_read_be32(fp, &iff.idsig) || |
1765 (idsig != IFF_ID_ILBM && idsig != IFF_ID_PBM)) | 1799 (iff.idsig != IFF_ID_ILBM && |
1800 iff.idsig != IFF_ID_PBM && | |
1801 iff.idsig != IFF_ID_ACBM)) | |
1766 { | 1802 { |
1767 return dmError(DMERR_INVALID_DATA, | 1803 return dmError(DMERR_INVALID_DATA, |
1768 "IFF: Not a IFF ILBM/PBM file.\n"); | 1804 "IFF: Not a IFF ILBM/PBM/ACBM file.\n"); |
1769 } | 1805 } |
1770 | |
1771 iff.planar = (idsig == IFF_ID_ILBM); | |
1772 | 1806 |
1773 dmMsg(3, "IFF: FORM is %s format image, with size %d bytes.\n", | 1807 dmMsg(3, "IFF: FORM is %s format image, with size %d bytes.\n", |
1774 iff.planar ? "ILBM" : "PBM", chunk.size); | 1808 iff.idsig == IFF_ID_ILBM ? "ILBM" : (iff.idsig == IFF_ID_PBM ? "PBM" : "ACBM"), |
1809 chunk.size); | |
1775 | 1810 |
1776 while (!parsed && !dmfeof(fp)) | 1811 while (!parsed && !dmfeof(fp)) |
1777 { | 1812 { |
1778 // Read chunk header | 1813 // Read chunk header |
1779 if ((res = dmReadIFFChunkHdr(fp, &chunk)) != DMERR_OK) | 1814 if ((res = dmReadIFFChunkHdr(fp, &chunk)) != DMERR_OK) |
1863 if (iff.chBMHD.count && iff.chBODY.count) | 1898 if (iff.chBMHD.count && iff.chBODY.count) |
1864 parsed = TRUE; | 1899 parsed = TRUE; |
1865 break; | 1900 break; |
1866 | 1901 |
1867 case IFF_ID_BODY: | 1902 case IFF_ID_BODY: |
1903 case IFF_ID_ABIT: | |
1868 // Check for multiple occurences of BODY | 1904 // Check for multiple occurences of BODY |
1869 if ((res = dmCheckIFFChunk(&iff.chBODY, &chunk, FALSE, 1)) != DMERR_OK) | 1905 if ((res = dmCheckIFFChunk(&iff.chBODY, &chunk, FALSE, 1)) != DMERR_OK) |
1870 return res; | 1906 return res; |
1871 | 1907 |
1872 // Check for sanity | 1908 // Check for sanity |
1873 if (!iff.chBMHD.count) | 1909 if (!iff.chBMHD.count) |
1874 { | 1910 { |
1875 return dmError(DMERR_INVALID_DATA, | 1911 return dmError(DMERR_INVALID_DATA, |
1876 "IFF: BODY chunk before BMHD?\n"); | 1912 "IFF: %s chunk before BMHD?\n", chunk.idStr); |
1877 } | 1913 } |
1878 | 1914 |
1879 dmMsg(2, "IFF: BODY chunk size %d bytes\n", chunk.size); | 1915 dmMsg(2, "IFF: %s chunk size %d bytes\n", chunk.idStr, chunk.size); |
1880 | 1916 |
1881 // Allocate image | 1917 // Allocate image |
1882 if ((*pimg = dmImageAlloc(iff.bmhd.w, iff.bmhd.h, | 1918 if ((*pimg = dmImageAlloc(iff.bmhd.w, iff.bmhd.h, |
1883 iff.bmhd.nplanes <= 8 ? DM_COLFMT_PALETTE : DM_COLFMT_RGBA, | 1919 iff.bmhd.nplanes <= 8 ? DM_COLFMT_PALETTE : DM_COLFMT_RGBA, |
1884 // XXX TODO? When/if we ever handle < 8bit indexed correctly, we can use the actual bpp | 1920 // XXX TODO? When/if we ever handle < 8bit indexed correctly, we can use the actual bpp |
1900 | 1936 |
1901 if (iff.chCMAP.count) | 1937 if (iff.chCMAP.count) |
1902 parsed = TRUE; | 1938 parsed = TRUE; |
1903 break; | 1939 break; |
1904 | 1940 |
1905 | |
1906 case IFF_ID_CAMG: | 1941 case IFF_ID_CAMG: |
1907 if (!dmf_read_be32(fp, &iff.camg)) | 1942 if (!dmf_read_be32(fp, &iff.camg)) |
1908 { | 1943 { |
1909 return dmError(DMERR_FREAD, | 1944 return dmError(DMERR_FREAD, |
1910 "IFF: Error reading CAMG chunk.\n"); | 1945 "IFF: Error reading CAMG chunk.\n"); |
1948 | 1983 |
1949 // If halfbrite is used, duplicate the palette | 1984 // If halfbrite is used, duplicate the palette |
1950 if (iff.camg & IFF_CAMG_HALFBRITE) | 1985 if (iff.camg & IFF_CAMG_HALFBRITE) |
1951 { | 1986 { |
1952 void *ptmp; | 1987 void *ptmp; |
1953 if (!iff.planar) | 1988 if (iff.idsig != IFF_ID_ILBM) |
1954 { | 1989 { |
1955 dmErrorMsg("IFF: Non-planar PBM file with Halfbrite enabled! This might not work.\n"); | 1990 dmErrorMsg("IFF: Non-planar PBM file with Halfbrite enabled! This might not work.\n"); |
1956 } | 1991 } |
1957 | 1992 |
1958 if (iff.ncolors > 128) | 1993 if (iff.ncolors > 128) |
2159 } | 2194 } |
2160 | 2195 |
2161 | 2196 |
2162 int dmWriteIFFImage(DMResource *fp, const DMImage *img, const DMImageConvSpec *cpspec) | 2197 int dmWriteIFFImage(DMResource *fp, const DMImage *img, const DMImageConvSpec *cpspec) |
2163 { | 2198 { |
2164 Uint32 idsig; | |
2165 DMIFF iff; | 2199 DMIFF iff; |
2166 Uint8 *buf = NULL; | 2200 Uint8 *buf = NULL; |
2167 size_t bufLen; | 2201 size_t bufLen; |
2168 int res = DMERR_OK; | 2202 int res = DMERR_OK; |
2169 DMImageConvSpec pspec, *spec = &pspec; | 2203 DMImageConvSpec pspec, *spec = &pspec; |
2194 iff.camg = 0; // XXX TODO: when/if HAM support | 2228 iff.camg = 0; // XXX TODO: when/if HAM support |
2195 iff.bmhd.masking = (img->ctransp < 0) ? IFF_MASK_NONE : spec->mask; | 2229 iff.bmhd.masking = (img->ctransp < 0) ? IFF_MASK_NONE : spec->mask; |
2196 iff.bmhd.compression = spec->compression ? IFF_COMP_BYTERUN1 : IFF_COMP_NONE; | 2230 iff.bmhd.compression = spec->compression ? IFF_COMP_BYTERUN1 : IFF_COMP_NONE; |
2197 iff.bmhd.transp = (img->ctransp >= 0 && spec->mask == IFF_MASK_TRANSP) ? img->ctransp : 0xffff; | 2231 iff.bmhd.transp = (img->ctransp >= 0 && spec->mask == IFF_MASK_TRANSP) ? img->ctransp : 0xffff; |
2198 iff.bmhd.nplanes = spec->nplanes; | 2232 iff.bmhd.nplanes = spec->nplanes; |
2199 idsig = spec->planar ? IFF_ID_ILBM : IFF_ID_PBM; | 2233 iff.idsig = spec->planar ? IFF_ID_ILBM : IFF_ID_PBM; |
2200 | 2234 |
2201 dmMsg(2, "IFF: nplanes=%d, comp=%d, mask=%d\n", | 2235 dmMsg(2, "IFF: nplanes=%d, comp=%d, mask=%d\n", |
2202 iff.bmhd.nplanes, iff.bmhd.compression, iff.bmhd.masking); | 2236 iff.bmhd.nplanes, iff.bmhd.compression, iff.bmhd.masking); |
2203 | 2237 |
2204 // Write IFF FORM header | 2238 // Write IFF FORM header |
2205 if ((res = dmWriteIFFChunkHdr(fp, &iff.chFORM, IFF_ID_FORM)) != DMERR_OK) | 2239 if ((res = dmWriteIFFChunkHdr(fp, &iff.chFORM, IFF_ID_FORM)) != DMERR_OK) |
2206 goto out; | 2240 goto out; |
2207 | 2241 |
2208 // Write IFF ILBM/PBM signature | 2242 // Write IFF ILBM/PBM signature |
2209 if (!dmf_write_be32(fp, idsig)) | 2243 if (!dmf_write_be32(fp, iff.idsig)) |
2210 { | 2244 { |
2211 res = dmError(DMERR_FWRITE, | 2245 res = dmError(DMERR_FWRITE, |
2212 "IFF: Error writing %s signature.\n", | 2246 "IFF: Error writing %s signature.\n", |
2213 spec->planar ? "ILBM" : "PBM"); | 2247 spec->planar ? "ILBM" : "PBM"); |
2214 goto out; | 2248 goto out; |
2390 "pcx", "Z-Soft Paintbrush", | 2424 "pcx", "Z-Soft Paintbrush", |
2391 DM_IMGFMT_PCX, DM_FMT_RDWR, | 2425 DM_IMGFMT_PCX, DM_FMT_RDWR, |
2392 fmtProbePCX, dmReadPCXImage, dmWritePCXImage, | 2426 fmtProbePCX, dmReadPCXImage, dmWritePCXImage, |
2393 }, | 2427 }, |
2394 { | 2428 { |
2395 "iff", "IFF ILBM / PBM", | 2429 "iff", "IFF ILBM/PBM/ACBM", |
2396 DM_IMGFMT_IFF, DM_FMT_RDWR, | 2430 DM_IMGFMT_IFF, DM_FMT_RDWR, |
2397 fmtProbeIFF, dmReadIFFImage, dmWriteIFFImage, | 2431 fmtProbeIFF, dmReadIFFImage, dmWriteIFFImage, |
2398 }, | 2432 }, |
2399 { | 2433 { |
2400 "raw", "Plain bitplaned (planar or non-planar) RAW", | 2434 "raw", "Plain bitplaned (planar or non-planar) RAW", |