comparison tools/libgfx.c @ 1896:f80b2dc77c30

Work begins on IFF ILBM/PBM image writer. It is pretty broken, some things will not work and some things are hardcoded. The ByteRun1 compression implementation is somewhat inefficient. Interleaved files do not work yet.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 26 Jun 2018 03:13:38 +0300
parents eb03869a10d3
children 50dbfc10f49f
comparison
equal deleted inserted replaced
1895:eb03869a10d3 1896:f80b2dc77c30
1910 1910
1911 return res; 1911 return res;
1912 } 1912 }
1913 1913
1914 1914
1915 static int dmWriteIFFChunkHdr(DMResource *fp, DMIFFChunk *chunk, const Uint32 id)
1916 {
1917 chunk->offs = dmftell(fp);
1918 chunk->id = id;
1919 dmMakeIFFChunkIDStr(chunk);
1920
1921 if (!dmf_write_be32(fp, chunk->id) ||
1922 !dmf_write_be32(fp, chunk->size))
1923 {
1924 return dmError(DMERR_FREAD,
1925 "IFF: Could not write IFF '%s' chunk header.\n",
1926 chunk->idStr);
1927 }
1928 else
1929 return DMERR_OK;
1930 }
1931
1932
1933 static int dmWriteIFFChunkFinish(DMResource *fp, DMIFFChunk *chunk)
1934 {
1935 off_t curr = dmftell(fp);
1936 if (curr < 0)
1937 return dmferror(fp);
1938
1939 chunk->size = curr - chunk->offs - (sizeof(Uint32) * 2);
1940 if ((chunk->size & 1) && !dmf_write_byte(fp, 0))
1941 return dmferror(fp);
1942
1943 if (dmfseek(fp, chunk->offs, SEEK_SET) < 0)
1944 return dmferror(fp);
1945
1946 if (!dmf_write_be32(fp, chunk->id) ||
1947 !dmf_write_be32(fp, chunk->size))
1948 {
1949 return dmError(DMERR_FREAD,
1950 "IFF: Could not write IFF '%s' chunk header.\n",
1951 chunk->idStr);
1952 }
1953
1954 if (dmfseek(fp, curr, SEEK_SET) < 0)
1955 return dmferror(fp);
1956
1957 return DMERR_OK;
1958 }
1959
1960
1961 enum
1962 {
1963 DMODE_LIT,
1964 DMODE_RLE,
1965 };
1966
1967
1968 BOOL dmIFFEncodeByteRun1Flush(
1969 DMResource *fp, const int mode, const BOOL flush,
1970 size_t *l_offs, const size_t offs, const Uint8 *buf,
1971 const Uint8 data, unsigned int *r_count)
1972 {
1973 if (mode == DMODE_LIT)
1974 {
1975 if (offs - *l_offs > *r_count || flush)
1976 {
1977 size_t count = (offs - *l_offs) - *r_count;
1978 Sint8 tmp = count - 1;
1979
1980 if (!dmf_write_byte(fp, tmp) ||
1981 !dmf_write_str(fp, buf + *l_offs, count))
1982 return FALSE;
1983 }
1984 (*r_count)++;
1985 }
1986 else
1987 {
1988 unsigned int count = *r_count;
1989 Sint8 tmp = -(count - 1);
1990
1991 if (!dmf_write_byte(fp, tmp) ||
1992 !dmf_write_byte(fp, data))
1993 return FALSE;
1994
1995 *r_count = 0;
1996 *l_offs = offs;
1997 }
1998
1999 return TRUE;
2000 }
2001
2002
2003 BOOL dmIFFEncodeByteRun1Row(DMResource *fp, const Uint8 *buf, const size_t bufLen)
2004 {
2005 size_t l_offs = 0, offs = 0;
2006 unsigned int r_count = 0;
2007 int prev = -1, mode = DMODE_LIT;
2008
2009 for (offs = 0; offs < bufLen; offs++)
2010 {
2011 Uint8 data = buf[offs];
2012 int next_mode;
2013
2014 if (data == prev)
2015 {
2016 r_count++;
2017 next_mode = DMODE_RLE;
2018 }
2019 else
2020 {
2021 next_mode = DMODE_LIT;
2022 }
2023
2024 BOOL flush = offs - l_offs >= 126 || r_count >= 126;
2025 if ((next_mode != mode || flush) &&
2026 !dmIFFEncodeByteRun1Flush(fp, mode, flush, &l_offs, offs, buf, prev, &r_count))
2027 return FALSE;
2028
2029 mode = next_mode;
2030 prev = data;
2031 }
2032
2033 if (!dmIFFEncodeByteRun1Flush(fp, mode, TRUE, &l_offs, offs, buf, prev, &r_count))
2034 return FALSE;
2035
2036 return TRUE;
2037 }
2038
2039
2040 static BOOL dmIFFWriteOneRow(DMResource *fp, DMIFF *iff, const Uint8 *buf, const size_t bufLen)
2041 {
2042 if (iff->bmhd.compression == IFF_COMP_BYTERUN1)
2043 return dmIFFEncodeByteRun1Row(fp, buf, bufLen);
2044 else
2045 return dmf_write_str(fp, buf, bufLen);
2046 }
2047
2048
2049 static inline Uint8 dmEncodeBit(const Uint8 *buf, const int xc)
2050 {
2051 return (buf[xc] >> (7 - (xc & 7))) & 1;
2052 }
2053
2054
2055 void dmEncodeBitPlane(Uint8 *dp, const Uint8 *src, const int width, const int nplane)
2056 {
2057 for (int xc = 0; xc < width; xc++)
2058 dp[xc / 8] |= dmEncodeBit(src, xc) << nplane;
2059 }
2060
2061
2062 int dmEncodeILBMBody(DMResource *fp, DMIFF *iff, const DMImage *img)
2063 {
2064 Uint8 *buf;
2065 size_t bufLen;
2066 int res = DMERR_OK;
2067 const int nplanes = iff->bmhd.nplanes;
2068
2069 // Allocate planar encoding buffer
2070 bufLen = ((img->width + 15) / 16) * 2;
2071 if ((buf = dmMalloc(bufLen)) == NULL)
2072 return DMERR_MALLOC;
2073
2074 dmMsg(2, "IFF: plane row size %d bytes.\n", bufLen);
2075
2076 // Encode the chunk
2077 for (int yc = 0; yc < img->height; yc++)
2078 {
2079 const Uint8 *sp = img->data + (yc * img->pitch);
2080
2081 dmMemset(buf, 0, bufLen);
2082
2083 for (int plane = 0; plane < nplanes; plane++)
2084 {
2085 // Encode bitplane
2086 dmEncodeBitPlane(buf, sp, img->width, plane);
2087
2088 // Compress / write data
2089 if (!dmIFFWriteOneRow(fp, iff, buf, bufLen))
2090 {
2091 res = dmError(DMERR_FWRITE,
2092 "IFF: Error in writing image plane #%d @ %d.\n",
2093 plane, yc);
2094 goto error;
2095 }
2096 }
2097 }
2098
2099 error:
2100 dmFree(buf);
2101 return res;
2102 }
2103
2104
2105 int dmEncodePBMBody(DMResource *fp, DMIFF *iff, const DMImage *img)
2106 {
2107 for (int yc = 0; yc < img->height; yc++)
2108 {
2109 if (!dmIFFWriteOneRow(fp, iff, img->data + (yc * img->pitch), img->width))
2110 {
2111 return dmError(DMERR_FWRITE,
2112 "IFF: Error writing PBM image row #%d.\n", yc);
2113 }
2114 }
2115
2116 return DMERR_OK;
2117 }
2118
2119
2120 int dmWriteIFFImage(DMResource *fp, const DMImage *img, const DMImageConvSpec *spec)
2121 {
2122 Uint32 idsig;
2123 DMIFF iff;
2124 int res = DMERR_OK;
2125
2126 // XXX: Non-paletted ILBM not supported!
2127 if (!spec->paletted)
2128 {
2129 return dmError(DMERR_NOT_SUPPORTED,
2130 "Non-paletted IFF is not supported.\n");
2131 }
2132
2133 // Setup headers
2134 iff.bmhd.x = 0;
2135 iff.bmhd.y = 0;
2136 iff.bmhd.w = img->width;
2137 iff.bmhd.h = img->height;
2138 iff.bmhd.pagew = img->width;
2139 iff.bmhd.pageh = img->height;
2140 iff.bmhd.pad1 = 0;
2141 iff.bmhd.xasp = 1; // XXX TODO: compute the xasp/yasp from the img->aspect
2142 iff.bmhd.yasp = 1;
2143
2144 iff.camg = 0; // XXX TODO: when/if HAM support
2145 iff.bmhd.masking = (img->ctransp < 0) ? IFF_MASK_NONE : spec->mask;
2146 iff.bmhd.compression = spec->compression ? IFF_COMP_BYTERUN1 : IFF_COMP_NONE;
2147 iff.bmhd.transp = (img->ctransp >= 0 && spec->mask == IFF_MASK_TRANSP) ? img->ctransp : 0xffff;
2148 iff.bmhd.nplanes = spec->nplanes;
2149 idsig = spec->planar ? IFF_ID_ILBM : IFF_ID_PBM;
2150
2151 dmMsg(2, "IFF: nplanes=%d, comp=%d, mask=%d\n",
2152 iff.bmhd.nplanes, iff.bmhd.compression, iff.bmhd.masking);
2153
2154 // Write IFF FORM header
2155 if ((res = dmWriteIFFChunkHdr(fp, &iff.chFORM, IFF_ID_FORM)) != DMERR_OK)
2156 goto out;
2157
2158 // Write IFF ILBM/PBM signature
2159 if (!dmf_write_be32(fp, idsig))
2160 {
2161 res = dmError(DMERR_FWRITE,
2162 "IFF: Error writing %s signature.\n",
2163 spec->planar ? "ILBM" : "PBM");
2164 goto out;
2165 }
2166
2167 // Write BMHD chunk and data
2168 if ((res = dmWriteIFFChunkHdr(fp, &iff.chBMHD, IFF_ID_BMHD)) != DMERR_OK ||
2169 !dmf_write_be16(fp, iff.bmhd.w) ||
2170 !dmf_write_be16(fp, iff.bmhd.h) ||
2171 !dmf_write_be16(fp, iff.bmhd.x) ||
2172 !dmf_write_be16(fp, iff.bmhd.y) ||
2173 !dmf_write_byte(fp, iff.bmhd.nplanes) ||
2174 !dmf_write_byte(fp, iff.bmhd.masking) ||
2175 !dmf_write_byte(fp, iff.bmhd.compression) ||
2176 !dmf_write_byte(fp, iff.bmhd.pad1) ||
2177 !dmf_write_be16(fp, iff.bmhd.transp) ||
2178 !dmf_write_byte(fp, iff.bmhd.xasp) ||
2179 !dmf_write_byte(fp, iff.bmhd.yasp) ||
2180 !dmf_write_be16(fp, iff.bmhd.pagew) ||
2181 !dmf_write_be16(fp, iff.bmhd.pageh))
2182 {
2183 res = dmError(DMERR_FWRITE,
2184 "IFF: Error writing BMHD chunk.\n");
2185 goto out;
2186 }
2187
2188 if ((res = dmWriteIFFChunkFinish(fp, &iff.chBMHD)) != DMERR_OK)
2189 goto out;
2190
2191 //
2192 // CMAP
2193 //
2194 if (img->ncolors > 0 && spec->paletted)
2195 {
2196 if ((res = dmWriteIFFChunkHdr(fp, &iff.chCMAP, IFF_ID_CMAP)) != DMERR_OK)
2197 goto out;
2198
2199 for (int i = 0; i < img->ncolors; i++)
2200 {
2201 DMColor *col = &img->pal[i];
2202 if (!dmf_write_byte(fp, col->r) ||
2203 !dmf_write_byte(fp, col->g) ||
2204 !dmf_write_byte(fp, col->b))
2205 {
2206 res = dmError(DMERR_FWRITE,
2207 "IFF: Could not write CMAP palette entry #%d.\n", i);
2208 goto out;
2209 }
2210 }
2211
2212 if ((res = dmWriteIFFChunkFinish(fp, &iff.chCMAP)) != DMERR_OK)
2213 goto out;
2214
2215 dmMsg(2, "IFF: CMAP %d entries (%d bytes)\n",
2216 img->ncolors, iff.chCMAP.size);
2217 }
2218
2219 //
2220 // CAMG
2221 //
2222 if ((res = dmWriteIFFChunkHdr(fp, &iff.chCMAP, IFF_ID_CAMG)) != DMERR_OK)
2223 goto out;
2224
2225 if (!dmf_write_be32(fp, iff.camg))
2226 {
2227 return dmError(DMERR_FREAD,
2228 "IFF: Error writing CAMG chunk.\n");
2229 }
2230
2231 if ((res = dmWriteIFFChunkFinish(fp, &iff.chCMAP)) != DMERR_OK)
2232 goto out;
2233
2234 //
2235 // Encode the body
2236 //
2237 if ((res = dmWriteIFFChunkHdr(fp, &iff.chBODY, IFF_ID_BODY)) != DMERR_OK)
2238 goto out;
2239
2240 if (spec->planar)
2241 {
2242 if ((res = dmEncodeILBMBody(fp, &iff, img)) != DMERR_OK)
2243 goto out;
2244 }
2245 else
2246 {
2247 if ((res = dmEncodePBMBody(fp, &iff, img)) != DMERR_OK)
2248 goto out;
2249 }
2250
2251 if ((res = dmWriteIFFChunkFinish(fp, &iff.chBODY)) != DMERR_OK)
2252 goto out;
2253
2254 // Finish the FORM chunk
2255 if ((res = dmWriteIFFChunkFinish(fp, &iff.chFORM)) != DMERR_OK)
2256 goto out;
2257
2258 out:
2259 return res;
2260 }
2261
2262
1915 // 2263 //
1916 // List of formats 2264 // List of formats
1917 // 2265 //
1918 const DMImageFormat dmImageFormatList[] = 2266 const DMImageFormat dmImageFormatList[] =
1919 { 2267 {
1935 fmtProbePCX, dmReadPCXImage, dmWritePCXImage, 2283 fmtProbePCX, dmReadPCXImage, dmWritePCXImage,
1936 }, 2284 },
1937 { 2285 {
1938 "iff", "IFF ILBM / PBM", 2286 "iff", "IFF ILBM / PBM",
1939 DM_IMGFMT_IFF, DM_FMT_RDWR, 2287 DM_IMGFMT_IFF, DM_FMT_RDWR,
1940 fmtProbeIFF, dmReadIFFImage, 2288 fmtProbeIFF, dmReadIFFImage, dmWriteIFFImage,
1941 NULL,
1942 }, 2289 },
1943 { 2290 {
1944 "raw", "Plain bitplaned (planar or non-planar) RAW", 2291 "raw", "Plain bitplaned (planar or non-planar) RAW",
1945 DM_IMGFMT_RAW, DM_FMT_WR, 2292 DM_IMGFMT_RAW, DM_FMT_WR,
1946 NULL, NULL, dmWriteRAWImage, 2293 NULL, NULL, dmWriteRAWImage,