Skip to content

Instantly share code, notes, and snippets.

@nico
Created October 14, 2012 23:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nico/3890115 to your computer and use it in GitHub Desktop.
Save nico/3890115 to your computer and use it in GitHub Desktop.
saving images
// uncompressed png, no dependencies
// from https://github.com/nico/hack/blob/master/wpng/wpng.c
void wpng(int w, int h, const uint8_t* pix, FILE* f) { // pix: rgba in memory
uint32_t crc_table[256];
for (uint32_t n = 0, c = 0; n < 256; n++, c = n) {
for (int k = 0; k < 8; k++) c = (c & 1) ? 0xedb88320L ^ (c >> 1) : c >> 1;
crc_table[n] = c;
}
#define CRCWRITE(d, len) fwrite(d, 1, len, f); for (int n = 0; n < len; n++) \
crc = crc_table[(crc ^ (d)[n]) & 0xff] ^ (crc >> 8)
uint8_t B[4];
#define U32BE(u) B[0] = (u) >> 24; B[1] = (u) >> 16; B[2] = (u) >> 8; B[3] = (u)
fwrite("\x89PNG\r\n\x1a\n\0\0\0\xdIHDR", 1, 16, f);
uint32_t crc = 0x575e51f5; // == update_crc(0xffffffff, "IHDR")
U32BE(w); CRCWRITE(B, 4);
U32BE(h); CRCWRITE(B, 4);
CRCWRITE("\x8\6\0\0\0", 5);
U32BE(crc ^ 0xffffffff); fwrite(B, 1, 4, f); // IHDR crc32
uint16_t scanline_size = w*4 + 1;
U32BE(6 + (5 + scanline_size)*h); fwrite(B, 1, 4, f);
crc = 0xffffffff;
CRCWRITE("IDAT\x8\x1d", 6);
uint32_t a1 = 1, a2 = 0;
for (int y = 0; y < h; ++y, pix += w*4) {
uint32_t s = scanline_size | (~scanline_size << 16);
uint8_t le[] = { y == h - 1 ? 1 : 0, s, s >> 8, s >> 16, s >> 24, 0 };
CRCWRITE(le, 6);
CRCWRITE(pix, w*4);
const int P = 65521;
a2 = (a1 + a2) % P;
for (int n = 0; n < w*4; n++) { a1 = (a1+pix[n]) % P; a2 = (a1+a2) % P; }
}
U32BE((a2 << 16) + a1); CRCWRITE(B, 4); // adler32 of uncompressed data
U32BE(crc ^ 0xffffffff); fwrite(B, 1, 4, f); // IDAT crc32
#undef CRCWRITE
#undef U32BE
fwrite("\0\0\0\0IEND\xae\x42\x60\x82", 1, 12, f); // IEND + crc32
}
// binary pgm
// (ppm is "P6")
// drawbacks: Preview.app / chrome can't read pgm. uncompressed.
// from https://github.com/nico/hack/blob/master/cv/graymap_pgm.c
bool save_graymap_to_pgm(const char* filename, const graymap_t* graymap) {
FILE* f = fopen(filename, "wb");
if (!f) return false;
const char kPgmHeader[] = "P5\n%d %d\n%d\n";
fprintf(f, kPgmHeader, graymap->w, graymap->h, 255);
fwrite(graymap->data, 1, graymap->w*graymap->h, f);
fclose(f);
return true;
}
// Any extension, using CoreGraphics
// from http://code.google.com/p/docerator/source/browse/trunk/flow.cpp
bool SaveImage(const char* name, const Img& img)
{
bool result = true;
CFStringRef pathString = NULL;
CFURLRef texture_url = NULL;
CGImageDestinationRef image_dest = NULL;
CGImageRef image = NULL;
CGColorSpaceRef color_space = NULL;
CGContextRef context = NULL;
unsigned char* dst = NULL;
pathString = CFStringCreateWithBytes(kCFAllocatorDefault,
(unsigned char*)name, strlen(name), kCFStringEncodingUTF8, NULL);
texture_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
pathString, kCFURLPOSIXPathStyle, FALSE);
if (!texture_url) { result = false; goto cleanup; }
dst = (unsigned char*)malloc(img.w * img.h * 4);
if (img.c == 1)
for (int y = 0; y < img.h; ++y) {
for (int x = 0; x < img.w; ++x) {
dst[y*img.w + x] = int(255*img.pix[y*img.w + x] + 0.5);
}
}
else
for (int y = 0; y < img.h; ++y) {
for (int x = 0; x < img.w; ++x) {
dst[4*(y*img.w + x) + 1] = int(255*img.pix[3*(y*img.w + x) + 0] + 0.5);
dst[4*(y*img.w + x) + 2] = int(255*img.pix[3*(y*img.w + x) + 1] + 0.5);
dst[4*(y*img.w + x) + 3] = int(255*img.pix[3*(y*img.w + x) + 2] + 0.5);
}
}
if (img.c == 1)
color_space = CGColorSpaceCreateDeviceGray();
else
color_space = CGColorSpaceCreateDeviceRGB();
// Since icns files are always a power of two, bytes per row are always a
// multiple of 8, as apple requires it
context = CGBitmapContextCreate(dst, img.w, img.h,
8, img.w * (img.c == 1 ? 1 : 4), color_space,
img.c == 1 ? kCGImageAlphaNone : kCGImageAlphaNoneSkipFirst);
image = CGBitmapContextCreateImage(context);
if (!image) { result = false; goto cleanup; }
image_dest
= CGImageDestinationCreateWithURL(texture_url, kUTTypePNG, 1, NULL);
if (!image_dest) { result = false; goto cleanup; }
CGImageDestinationAddImage(image_dest, image, NULL);
if (!CGImageDestinationFinalize(image_dest))
result = false;
cleanup:
if (pathString) CFRelease(pathString);
if (context) CFRelease(context);
if (color_space) CFRelease(color_space);
if (image) CFRelease(image);
if (image_dest) CFRelease(image_dest);
if (texture_url) CFRelease(texture_url);
if (dst) free(dst);
assert(result);
return result;
}
# png, using cocoa
# from https://gist.github.com/3161796
// (similar code in https://github.com/nico/hack/blob/master/cv/train_mac.m)
def saverep(rep, path):
rep.representationUsingType_properties_(NSPNGFileType, None) \
.writeToFile_atomically_(path, True)
def saveimg(img, path):
s = img.size()
img.lockFocus()
bitmapRep = NSBitmapImageRep.alloc().initWithFocusedViewRect_(((0, 0), s))
img.unlockFocus()
saverep(bitmapRep, path)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment