terom@0: #include "image.h" terom@19: #include "ctx.h" terom@56: #include "png.h" terom@1: #include "cache.h" terom@18: #include "tile.h" terom@17: #include "error.h" terom@4: #include "shared/util.h" terom@19: #include "shared/log.h" terom@0: terom@1: #include terom@54: #include terom@54: #include terom@6: #include terom@1: terom@17: static int pt_image_new (struct pt_image **image_ptr, struct pt_ctx *ctx, const char *path) terom@0: { terom@17: struct pt_image *image; terom@17: int err = 0; terom@0: terom@0: // alloc terom@17: if ((image = calloc(1, sizeof(*image))) == NULL) terom@17: JUMP_SET_ERROR(err, PT_ERR_MEM); terom@0: terom@17: if ((image->path = strdup(path)) == NULL) terom@17: JUMP_SET_ERROR(err, PT_ERR_MEM); terom@0: terom@0: // init terom@17: image->ctx = ctx; terom@0: terom@0: // ok terom@17: *image_ptr = image; terom@0: terom@0: return 0; terom@0: terom@0: error: terom@17: pt_image_destroy(image); terom@17: terom@17: return err; terom@0: } terom@0: terom@0: /** 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@17: if (path_with_fext(image->path, buf, len, ".cache")) terom@17: RETURN_ERROR(PT_ERR_PATH); terom@17: terom@17: return 0; 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@17: int err; terom@1: terom@69: // verify that the path exists and looks like a PNG file terom@69: if ((err = pt_png_check(path)) < 0) terom@69: return err; terom@69: terom@69: if (err) terom@69: // fail, not a PNG terom@69: RETURN_ERROR(PT_ERR_IMG_FORMAT); terom@0: terom@0: // alloc terom@17: if ((err = pt_image_new(&image, ctx, path))) terom@17: return err; terom@1: terom@1: // compute cache file path terom@17: if ((err = pt_image_cache_path(image, cache_path, sizeof(cache_path)))) terom@17: JUMP_ERROR(err); terom@0: terom@9: // create the cache object for this image (doesn't yet open it) terom@17: if ((err = pt_cache_new(&image->cache, cache_path, cache_mode))) terom@17: JUMP_ERROR(err); 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@17: return err; terom@0: } terom@1: terom@56: int pt_image_open_file (struct pt_image *image, FILE **file_ptr) terom@56: { terom@56: FILE *fp; terom@56: terom@56: // open terom@56: if ((fp = fopen(image->path, "rb")) == NULL) terom@69: RETURN_ERROR(PT_ERR_IMG_OPEN); terom@56: terom@56: // ok terom@56: *file_ptr = fp; terom@56: terom@56: return 0; terom@56: } terom@56: terom@56: /** terom@56: * Open the PNG image, and write out to the cache terom@56: */ terom@56: int pt_image_update (struct pt_image *image, const struct pt_image_params *params) terom@56: { terom@56: struct pt_png_img img; terom@56: int err = 0; terom@56: terom@56: // pre-check enabled terom@56: if (!(image->cache->mode & PT_OPEN_UPDATE)) terom@56: RETURN_ERROR_ERRNO(PT_ERR_OPEN_MODE, EACCES); terom@56: terom@56: // open .png terom@56: if ((err = pt_png_open(image, &img))) terom@56: return err; terom@56: terom@56: // pass to cache object terom@56: if ((err = pt_cache_update(image->cache, &img, params))) terom@56: JUMP_ERROR(err); terom@56: terom@56: error: terom@56: // clean up terom@56: pt_png_release_read(&img); terom@56: terom@56: return err; terom@56: } terom@56: terom@56: terom@7: int pt_image_info (struct pt_image *image, const struct pt_image_info **info_ptr) terom@7: { terom@54: struct stat st; terom@17: terom@56: // update info from cache terom@56: pt_cache_info(image->cache, &image->info); terom@54: terom@54: // stat our info terom@54: if (stat(image->path, &st) < 0) { terom@54: // unknown terom@54: image->info.image_mtime = 0; terom@54: image->info.image_bytes = 0; terom@54: terom@54: } else { terom@54: // store terom@54: image->info.image_mtime = st.st_mtime; terom@54: image->info.image_bytes = st.st_size; terom@54: } terom@10: terom@10: // return pointer 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: terom@25: int pt_image_load (struct pt_image *image) terom@25: { terom@25: return pt_cache_open(image->cache); terom@25: } terom@25: terom@18: int pt_image_tile_file (struct pt_image *image, const struct pt_tile_info *info, FILE *out) terom@9: { terom@18: struct pt_tile tile; terom@18: int err; terom@9: terom@18: // init terom@19: if ((err = pt_tile_init_file(&tile, image->cache, info, out))) terom@18: return err; terom@18: terom@18: // render terom@19: if ((err = pt_tile_render(&tile))) terom@17: JUMP_ERROR(err); terom@9: terom@18: // ok terom@18: return 0; terom@9: terom@9: error: terom@18: pt_tile_abort(&tile); terom@18: terom@18: return err; terom@18: } terom@18: terom@18: int pt_image_tile_mem (struct pt_image *image, const struct pt_tile_info *info, char **buf_ptr, size_t *len_ptr) terom@18: { terom@18: struct pt_tile tile; terom@18: int err; terom@18: terom@18: // init terom@19: if ((err = pt_tile_init_mem(&tile, image->cache, info))) terom@18: return err; terom@18: terom@18: // render terom@19: if ((err = pt_tile_render(&tile))) terom@18: JUMP_ERROR(err); terom@18: terom@18: // ok terom@18: *buf_ptr = tile.out.mem.base; terom@18: *len_ptr = tile.out.mem.len; terom@18: terom@18: return 0; terom@18: terom@18: error: terom@18: pt_tile_abort(&tile); terom@9: terom@17: return err; terom@9: } terom@9: terom@64: /** terom@64: * Async work func for pt_image_tile_async terom@64: */ terom@19: static void _pt_image_tile_async (void *arg) terom@19: { terom@19: struct pt_tile *tile = arg; terom@19: int err; terom@19: terom@19: // do render op terom@19: if ((err = pt_tile_render(tile))) terom@19: log_warn_errno("pt_tile_render: %s", pt_strerror(err)); terom@19: terom@19: // signal done terom@19: if (fclose(tile->out.file)) terom@19: log_warn_errno("fclose"); terom@22: terom@22: // cleanup terom@22: pt_tile_destroy(tile); terom@19: } terom@19: terom@19: int pt_image_tile_async (struct pt_image *image, const struct pt_tile_info *info, FILE *out) terom@19: { terom@19: struct pt_tile *tile; terom@19: int err; terom@19: terom@64: // need a ctx for this terom@64: if (!image->ctx) terom@64: return -1; terom@64: terom@19: // alloc terom@19: if ((err = pt_tile_new(&tile))) terom@19: return err; terom@19: terom@19: // init terom@19: if ((err = pt_tile_init_file(tile, image->cache, info, out))) terom@19: JUMP_ERROR(err); terom@19: terom@19: // enqueue work terom@19: if ((err = pt_ctx_work(image->ctx, _pt_image_tile_async, tile))) terom@19: JUMP_ERROR(err); terom@19: terom@19: // ok, running terom@19: return 0; terom@19: terom@19: error: terom@19: pt_tile_destroy(tile); terom@19: terom@19: return err; terom@19: } terom@19: 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: } terom@19: