Created
October 14, 2012 23:10
-
-
Save nico/3890115 to your computer and use it in GitHub Desktop.
saving images
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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