terom@0: #include "image.h" terom@1: #include "cache.h" terom@4: #include "shared/util.h" terom@0: terom@1: #include terom@6: #include terom@1: terom@1: #include terom@1: terom@1: static int pt_image_new (struct pt_image **img_ptr, struct pt_ctx *ctx, const char *path) terom@0: { terom@0: struct pt_image *img; terom@0: terom@0: // alloc terom@0: if ((img = calloc(1, sizeof(*img))) == NULL) terom@0: return -1; terom@0: terom@1: if ((img->path = strdup(path)) == NULL) terom@0: goto error; terom@0: terom@0: // init terom@0: img->ctx = ctx; terom@0: terom@0: // ok terom@0: *img_ptr = img; terom@0: terom@0: return 0; terom@0: terom@0: error: terom@0: pt_image_destroy(img); terom@0: terom@0: return -1; terom@0: } terom@0: terom@0: /** terom@0: * Open the image's FILE terom@0: */ terom@0: static int pt_image_open_file (struct pt_image *img, FILE **file_ptr) terom@0: { terom@0: FILE *fp; terom@0: terom@0: // open terom@2: if ((fp = fopen(img->path, "rb")) < 0) terom@0: return -1; terom@0: terom@0: // ok terom@0: *file_ptr = fp; terom@0: terom@0: return 0; terom@0: } terom@0: terom@0: /** terom@0: * Open the PNG image, setting up the I/O and returning the png_structp and png_infop terom@0: */ terom@0: static int pt_image_open_png (struct pt_image *img, png_structp *png_ptr, png_infop *info_ptr) terom@0: { terom@0: FILE *fp = NULL; terom@0: png_structp png = NULL; terom@0: png_infop info = NULL; terom@0: terom@0: // open I/O terom@0: if (pt_image_open_file(img, &fp)) terom@0: goto error; terom@0: terom@0: // create the struct terom@0: if ((png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) terom@0: goto error; terom@0: terom@0: // create the info terom@0: if ((info = png_create_info_struct(png)) == NULL) terom@0: goto error; terom@0: terom@0: // setup error trap for the I/O terom@0: if (setjmp(png_jmpbuf(png))) terom@0: goto error; terom@0: terom@0: // setup I/O to FILE terom@0: png_init_io(png, fp); terom@0: terom@0: // ok terom@1: // XXX: what to do with fp? terom@0: *png_ptr = png; terom@0: *info_ptr = info; terom@0: terom@0: return 0; terom@0: terom@0: error: terom@0: // cleanup file terom@0: if (fp) fclose(fp); terom@0: terom@0: // cleanup PNG state terom@0: png_destroy_read_struct(&png, &info, NULL); terom@0: terom@0: return -1; terom@0: } terom@0: terom@0: /** terom@7: * Update the image_info field from the given png object. terom@7: * terom@7: * Must be called under libpng-error-trap! terom@7: */ terom@7: static int pt_image_update_info (struct pt_image *image, png_structp png, png_infop info) terom@7: { terom@7: // query png_get_* terom@7: image->info.width = png_get_image_width(png, info); terom@7: image->info.height = png_get_image_height(png, info); terom@7: terom@7: return 0; terom@7: } terom@7: terom@7: /** terom@0: * Open the PNG image, and write out to the cache terom@0: */ terom@6: static int pt_image_update_cache (struct pt_image *image) terom@0: { terom@0: png_structp png; terom@0: png_infop info; terom@0: terom@6: // pre-check enabled terom@6: if (!(image->cache->mode & PT_IMG_WRITE)) { terom@6: errno = EPERM; terom@6: return -1; terom@6: } terom@6: terom@0: // open .png terom@6: if (pt_image_open_png(image, &png, &info)) terom@0: return -1; terom@0: terom@0: // setup error trap terom@0: if (setjmp(png_jmpbuf(png))) terom@0: goto error; terom@0: terom@0: // read meta-info terom@0: png_read_info(png, info); terom@0: terom@7: // update our meta-info terom@7: if (pt_image_update_info(image, png, info)) terom@7: goto error; terom@7: terom@0: // pass to cache object terom@6: if (pt_cache_update_png(image->cache, png, info)) terom@0: goto error; terom@0: terom@0: // finish off, ignore trailing data terom@0: png_read_end(png, NULL); terom@0: terom@0: // clean up terom@1: png_destroy_read_struct(&png, &info, NULL); terom@0: terom@0: return 0; terom@0: terom@0: error: terom@0: // clean up terom@1: png_destroy_read_struct(&png, &info, NULL); terom@0: terom@0: return -1; terom@0: } terom@0: terom@1: /** terom@1: * Build a filesystem path representing the appropriate path for this image's cache entry, and store it in the given terom@1: * buffer. terom@1: */ terom@1: static int pt_image_cache_path (struct pt_image *image, char *buf, size_t len) terom@0: { terom@4: return path_with_fext(image->path, buf, len, ".cache"); terom@1: } terom@0: terom@1: int pt_image_open (struct pt_image **image_ptr, struct pt_ctx *ctx, const char *path, int cache_mode) terom@1: { terom@1: struct pt_image *image; terom@6: char cache_path[1024]; terom@1: terom@1: // XXX: verify that the path exists and looks like a PNG file terom@0: terom@0: // alloc terom@1: if (pt_image_new(&image, ctx, path)) terom@0: return -1; terom@1: terom@1: // compute cache file path terom@1: if (pt_image_cache_path(image, cache_path, sizeof(cache_path))) terom@1: goto error; terom@0: terom@0: // open the cache object for this image terom@1: if (pt_cache_open(&image->cache, cache_path, cache_mode)) terom@0: goto error; terom@0: terom@0: // ok, ready for access terom@1: *image_ptr = image; terom@0: terom@0: return 0; terom@0: terom@0: error: terom@1: pt_image_destroy(image); terom@1: terom@1: return -1; terom@0: } terom@1: terom@7: int pt_image_info (struct pt_image *image, const struct pt_image_info **info_ptr) terom@7: { terom@7: // XXX: ensure that this was read? terom@7: *info_ptr = &image->info; terom@7: terom@7: return 0; terom@7: } terom@7: terom@8: int pt_image_status (struct pt_image *image) terom@5: { terom@8: return pt_cache_status(image->cache, image->path); terom@5: } terom@5: terom@5: int pt_image_update (struct pt_image *image) terom@5: { terom@5: return pt_image_update_cache(image); terom@5: } terom@5: terom@1: void pt_image_destroy (struct pt_image *image) terom@1: { terom@1: free(image->path); terom@1: terom@1: if (image->cache) terom@1: pt_cache_destroy(image->cache); terom@1: terom@1: free(image); terom@1: }