| 253 | } |
| 254 | |
| 255 | int save_png(const char *filename, SDL_Surface *image) |
| 256 | { |
| 257 | uchar *data = (uchar *)image->pixels; |
| 258 | int iw = image->w, ih = image->h, pitch = image->pitch; |
| 259 | |
| 260 | stream *f = openfile(filename, "wb"); |
| 261 | if(!f) { conoutf("could not write to %s", filename); return -1; } |
| 262 | const char *scores = asciiscores(true); |
| 263 | |
| 264 | uchar signature[] = { 137, 80, 78, 71, 13, 10, 26, 10 }; |
| 265 | f->write(signature, sizeof(signature)); |
| 266 | |
| 267 | struct pngihdr |
| 268 | { |
| 269 | uint width, height; |
| 270 | uchar bitdepth, colortype, compress, filter, interlace; |
| 271 | } ihdr = { bigswap<uint>(iw), bigswap<uint>(ih), 8, 2, 0, 0, 0 }; |
| 272 | writepngchunk(f, "IHDR", (uchar *)&ihdr, 13); |
| 273 | |
| 274 | int idat = f->tell(); |
| 275 | uint len = 0; |
| 276 | f->write("\0\0\0\0IDAT", 8); |
| 277 | uint crc = crc32(0, Z_NULL, 0); |
| 278 | crc = crc32(crc, (const Bytef *)"IDAT", 4); |
| 279 | |
| 280 | z_stream z; |
| 281 | z.zalloc = NULL; |
| 282 | z.zfree = NULL; |
| 283 | z.opaque = NULL; |
| 284 | |
| 285 | if(deflateInit(&z, pngcompress) != Z_OK) |
| 286 | goto error; |
| 287 | |
| 288 | uchar buf[1<<12]; |
| 289 | z.next_out = (Bytef *)buf; |
| 290 | z.avail_out = sizeof(buf); |
| 291 | |
| 292 | loopi(ih) |
| 293 | { |
| 294 | uchar filter = 0; |
| 295 | loopj(2) |
| 296 | { |
| 297 | z.next_in = j ? (Bytef *)data + i*pitch : (Bytef *)&filter; |
| 298 | z.avail_in = j ? iw*3 : 1; |
| 299 | while(z.avail_in > 0) |
| 300 | { |
| 301 | if(deflate(&z, Z_NO_FLUSH) != Z_OK) goto cleanuperror; |
| 302 | #define FLUSHZ do { \ |
| 303 | int flush = sizeof(buf) - z.avail_out; \ |
| 304 | crc = crc32(crc, buf, flush); \ |
| 305 | len += flush; \ |
| 306 | f->write(buf, flush); \ |
| 307 | z.next_out = (Bytef *)buf; \ |
| 308 | z.avail_out = sizeof(buf); \ |
| 309 | } while(0) |
| 310 | FLUSHZ; |
| 311 | } |
| 312 | } |
no test coverage detected