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",