dt_imageio_retval_t dt_imageio_open_pfm(dt_image_t *img, const char *filename, dt_mipmap_cache_allocator_t a) { const char *ext = filename + strlen(filename); while(*ext != '.' && ext > filename) ext--; if(strcasecmp(ext, ".pfm")) return DT_IMAGEIO_FILE_CORRUPTED; FILE *f = fopen(filename, "rb"); if(!f) return DT_IMAGEIO_FILE_CORRUPTED; int ret = 0; int cols = 3; char head[2] = { 'X', 'X' }; ret = fscanf(f, "%c%c\n", head, head + 1); if(ret != 2 || head[0] != 'P') goto error_corrupt; if(head[1] == 'F') cols = 3; else if(head[1] == 'f') cols = 1; else goto error_corrupt; ret = fscanf(f, "%d %d\n%*[^\n]", &img->width, &img->height); if(ret != 2) goto error_corrupt; ret = fread(&ret, sizeof(char), 1, f); if(ret != 1) goto error_corrupt; ret = 0; float *buf = (float *)dt_mipmap_cache_alloc(img, DT_MIPMAP_FULL, a); if(!buf) goto error_cache_full; if(cols == 3) { ret = fread(buf, 3 * sizeof(float), (size_t)img->width * img->height, f); for(size_t i = (size_t)img->width * img->height; i > 0; i--) for(int c = 0; c < 3; c++) buf[4 * (i - 1) + c] = fmaxf(0.0f, fminf(FLT_MAX, buf[3 * (i - 1) + c])); } else for(size_t j = 0; j < img->height; j++) for(size_t i = 0; i < img->width; i++) { ret = fread(buf + 4 * (img->width * j + i), sizeof(float), 1, f); buf[4 * (img->width * j + i) + 2] = buf[4 * (img->width * j + i) + 1] = buf[4 * (img->width * j + i) + 0]; } float *line = (float *)calloc(4 * img->width, sizeof(float)); for(size_t j = 0; j < img->height / 2; j++) { memcpy(line, buf + img->width * j * 4, 4 * sizeof(float) * img->width); memcpy(buf + img->width * j * 4, buf + img->width * (img->height - 1 - j) * 4, 4 * sizeof(float) * img->width); memcpy(buf + img->width * (img->height - 1 - j) * 4, line, 4 * sizeof(float) * img->width); } free(line); fclose(f); return DT_IMAGEIO_OK; error_corrupt: fclose(f); return DT_IMAGEIO_FILE_CORRUPTED; error_cache_full: fclose(f); return DT_IMAGEIO_CACHE_FULL; }
// transparent read method to load ldr image to dt_raw_image_t with exif and so on. dt_imageio_retval_t dt_imageio_open_ldr( dt_image_t *img, const char *filename, dt_mipmap_cache_allocator_t a) { dt_imageio_retval_t ret; ret = dt_imageio_open_tiff(img, filename, a); if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL) { img->filters = 0; img->flags &= ~DT_IMAGE_RAW; img->flags &= ~DT_IMAGE_HDR; img->flags |= DT_IMAGE_LDR; return ret; } // jpeg stuff here: if(!img->exif_inited) (void) dt_exif_read(img, filename); const int orientation = dt_image_orientation(img); dt_imageio_jpeg_t jpg; if(dt_imageio_jpeg_read_header(filename, &jpg)) return DT_IMAGEIO_FILE_CORRUPTED; img->width = (orientation & 4) ? jpg.height : jpg.width; img->height = (orientation & 4) ? jpg.width : jpg.height; uint8_t *tmp = (uint8_t *)malloc(sizeof(uint8_t)*jpg.width*jpg.height*4); if(dt_imageio_jpeg_read(&jpg, tmp)) { free(tmp); return DT_IMAGEIO_FILE_CORRUPTED; } img->bpp = 4*sizeof(float); void *buf = dt_mipmap_cache_alloc(img, DT_MIPMAP_FULL, a); if(!buf) { free(tmp); return DT_IMAGEIO_CACHE_FULL; } dt_imageio_flip_buffers_ui8_to_float((float *)buf, tmp, 0.0f, 255.0f, 4, jpg.width, jpg.height, jpg.width, jpg.height, 4*jpg.width, orientation); free(tmp); img->filters = 0; img->flags &= ~DT_IMAGE_RAW; img->flags &= ~DT_IMAGE_HDR; img->flags |= DT_IMAGE_LDR; return DT_IMAGEIO_OK; }
dt_imageio_retval_t dt_imageio_open_jpeg(dt_image_t *img, const char *filename, dt_mipmap_cache_allocator_t a) { const char *ext = filename + strlen(filename); while(*ext != '.' && ext > filename) ext--; if(strncmp(ext, ".jpg", 4) && strncmp(ext, ".JPG", 4) && strncmp(ext, ".jpeg", 5) && strncmp(ext, ".JPEG", 5)) return DT_IMAGEIO_FILE_CORRUPTED; if(!img->exif_inited) (void) dt_exif_read(img, filename); const int orientation = dt_image_orientation(img); dt_imageio_jpeg_t jpg; if(dt_imageio_jpeg_read_header(filename, &jpg)) return DT_IMAGEIO_FILE_CORRUPTED; img->width = (orientation & 4) ? jpg.height : jpg.width; img->height = (orientation & 4) ? jpg.width : jpg.height; uint8_t *tmp = (uint8_t *)malloc(sizeof(uint8_t)*jpg.width*jpg.height*4); if(dt_imageio_jpeg_read(&jpg, tmp)) { free(tmp); return DT_IMAGEIO_FILE_CORRUPTED; } img->bpp = 4*sizeof(float); void *buf = dt_mipmap_cache_alloc(img, DT_MIPMAP_FULL, a); if(!buf) { free(tmp); return DT_IMAGEIO_CACHE_FULL; } dt_imageio_flip_buffers_ui8_to_float((float *)buf, tmp, 0.0f, 255.0f, 4, jpg.width, jpg.height, jpg.width, jpg.height, 4*jpg.width, orientation); free(tmp); return DT_IMAGEIO_OK; }
dt_imageio_retval_t dt_imageio_open_pnm(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf) { const char *ext = filename + strlen(filename); while(*ext != '.' && ext > filename) ext--; if(strcasecmp(ext, ".pbm") && strcasecmp(ext, ".pgm") && strcasecmp(ext, ".ppm")) return DT_IMAGEIO_FILE_CORRUPTED; FILE *f = g_fopen(filename, "rb"); if(!f) return DT_IMAGEIO_FILE_CORRUPTED; int ret = 0; dt_imageio_retval_t result = DT_IMAGEIO_FILE_CORRUPTED; char head[2] = { 'X', 'X' }; ret = fscanf(f, "%c%c ", head, head + 1); if(ret != 2 || head[0] != 'P') goto end; ret = fscanf(f, "%d %d ", &img->width, &img->height); if(ret != 2) goto end; img->buf_dsc.channels = 4; img->buf_dsc.datatype = TYPE_FLOAT; float *buf = (float *)dt_mipmap_cache_alloc(mbuf, img); if(!buf) { result = DT_IMAGEIO_CACHE_FULL; goto end; } // we don't support ASCII variants or P7 anymaps! thanks to magic numbers those shouldn't reach us anyway. if(head[1] == '4') result = _read_pbm(img, f, buf); else if(head[1] == '5') result = _read_pgm(img, f, buf); else if(head[1] == '6') result = _read_ppm(img, f, buf); end: fclose(f); return result; }
// open a raw file, libraw path: dt_imageio_retval_t dt_imageio_open_raw( dt_image_t *img, const char *filename, dt_mipmap_cache_allocator_t a) { if(!img->exif_inited) (void) dt_exif_read(img, filename); int ret; libraw_data_t *raw = libraw_init(0); libraw_processed_image_t *image = NULL; raw->params.half_size = 0; /* dcraw -h */ raw->params.use_camera_wb = 0; raw->params.use_auto_wb = 0; raw->params.med_passes = 0;//img->raw_params.med_passes; raw->params.no_auto_bright = 1; // raw->params.filtering_mode |= LIBRAW_FILTERING_NOBLACKS; // raw->params.document_mode = 2; // no color scaling, no black, no max, no wb..? raw->params.document_mode = 2; // color scaling (clip,wb,max) and black point, but no demosaic raw->params.output_color = 0; raw->params.output_bps = 16; raw->params.user_flip = -1; // -1 means: use orientation from raw raw->params.gamm[0] = 1.0; raw->params.gamm[1] = 1.0; // raw->params.user_qual = img->raw_params.demosaic_method; // 3: AHD, 2: PPG, 1: VNG raw->params.user_qual = 0; // raw->params.four_color_rgb = img->raw_params.four_color_rgb; raw->params.four_color_rgb = 0; raw->params.use_camera_matrix = 0; raw->params.green_matching = 0; raw->params.highlight = 1; raw->params.threshold = 0; // raw->params.auto_bright_thr = img->raw_auto_bright_threshold; // raw->params.amaze_ca_refine = 0; raw->params.fbdd_noiserd = 0; ret = libraw_open_file(raw, filename); HANDLE_ERRORS(ret, 0); raw->params.user_qual = 0; raw->params.half_size = 0; ret = libraw_unpack(raw); // img->black = raw->color.black/65535.0; // img->maximum = raw->color.maximum/65535.0; img->bpp = sizeof(uint16_t); // printf("black, max: %d %d %f %f\n", raw->color.black, raw->color.maximum, img->black, img->maximum); HANDLE_ERRORS(ret, 1); ret = libraw_dcraw_process(raw); // ret = libraw_dcraw_document_mode_processing(raw); HANDLE_ERRORS(ret, 1); image = libraw_dcraw_make_mem_image(raw, &ret); HANDLE_ERRORS(ret, 1); // fallback for broken exif read in case of phase one H25 if(!strncmp(img->exif_maker, "Phase One", 9)) img->orientation = raw->sizes.flip; // filters seem only ever to take a useful value after unpack/process img->filters = raw->idata.filters; img->width = (img->orientation & 4) ? raw->sizes.height : raw->sizes.width; img->height = (img->orientation & 4) ? raw->sizes.width : raw->sizes.height; img->exif_iso = raw->other.iso_speed; img->exif_exposure = raw->other.shutter; img->exif_aperture = raw->other.aperture; img->exif_focal_length = raw->other.focal_len; g_strlcpy(img->exif_maker, raw->idata.make, sizeof(img->exif_maker)); img->exif_maker[sizeof(img->exif_maker) - 1] = 0x0; g_strlcpy(img->exif_model, raw->idata.model, sizeof(img->exif_model)); img->exif_model[sizeof(img->exif_model) - 1] = 0x0; dt_gettime_t(img->exif_datetime_taken, raw->other.timestamp); void *buf = dt_mipmap_cache_alloc(img, DT_MIPMAP_FULL, a); if(!buf) { libraw_recycle(raw); libraw_close(raw); free(image); return DT_IMAGEIO_CACHE_FULL; } #ifdef _OPENMP #pragma omp parallel for schedule(static) default(none) shared(img, image, raw, buf) #endif for(int k=0; k<img->width*img->height; k++) ((uint16_t *)buf)[k] = CLAMPS((((uint16_t *)image->data)[k] - raw->color.black)*65535.0f/(float)(raw->color.maximum - raw->color.black), 0, 0xffff); // clean up raw stuff. libraw_recycle(raw); libraw_close(raw); free(image); raw = NULL; image = NULL; img->flags &= ~DT_IMAGE_LDR; img->flags &= ~DT_IMAGE_HDR; img->flags |= DT_IMAGE_RAW; return DT_IMAGEIO_OK; }
dt_imageio_retval_t dt_imageio_open_pfm(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf) { const char *ext = filename + strlen(filename); while(*ext != '.' && ext > filename) ext--; if(strcasecmp(ext, ".pfm")) return DT_IMAGEIO_FILE_CORRUPTED; FILE *f = fopen(filename, "rb"); if(!f) return DT_IMAGEIO_FILE_CORRUPTED; int ret = 0; int cols = 3; float scale_factor; char head[2] = { 'X', 'X' }; ret = fscanf(f, "%c%c\n", head, head + 1); if(ret != 2 || head[0] != 'P') goto error_corrupt; if(head[1] == 'F') cols = 3; else if(head[1] == 'f') cols = 1; else goto error_corrupt; ret = fscanf(f, "%d %d %f%*[^\n]", &img->width, &img->height, &scale_factor); if(ret != 3) goto error_corrupt; ret = fread(&ret, sizeof(char), 1, f); if(ret != 1) goto error_corrupt; ret = 0; int swap_byte_order = (scale_factor >= 0.0) ^ (G_BYTE_ORDER == G_BIG_ENDIAN); float *buf = (float *)dt_mipmap_cache_alloc(mbuf, img); if(!buf) goto error_cache_full; if(cols == 3) { ret = fread(buf, 3 * sizeof(float), (size_t)img->width * img->height, f); for(size_t i = (size_t)img->width * img->height; i > 0; i--) for(int c = 0; c < 3; c++) { union { float f; guint32 i; } v; v.f = buf[3 * (i - 1) + c]; if(swap_byte_order) v.i = GUINT32_SWAP_LE_BE(v.i); buf[4 * (i - 1) + c] = fmaxf(0.0f, fminf(FLT_MAX, v.f)); } } else for(size_t j = 0; j < img->height; j++) for(size_t i = 0; i < img->width; i++) { union { float f; guint32 i; } v; ret = fread(&v.f, sizeof(float), 1, f); if(swap_byte_order) v.i = GUINT32_SWAP_LE_BE(v.i); buf[4 * (img->width * j + i) + 2] = buf[4 * (img->width * j + i) + 1] = buf[4 * (img->width * j + i) + 0] = v.f; } float *line = (float *)calloc(4 * img->width, sizeof(float)); for(size_t j = 0; j < img->height / 2; j++) { memcpy(line, buf + img->width * j * 4, 4 * sizeof(float) * img->width); memcpy(buf + img->width * j * 4, buf + img->width * (img->height - 1 - j) * 4, 4 * sizeof(float) * img->width); memcpy(buf + img->width * (img->height - 1 - j) * 4, line, 4 * sizeof(float) * img->width); } free(line); fclose(f); return DT_IMAGEIO_OK; error_corrupt: fclose(f); return DT_IMAGEIO_FILE_CORRUPTED; error_cache_full: fclose(f); return DT_IMAGEIO_CACHE_FULL; }
dt_imageio_retval_t dt_imageio_open_png(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf) { const char *ext = filename + strlen(filename); while(*ext != '.' && ext > filename) ext--; if(strncmp(ext, ".png", 4) && strncmp(ext, ".PNG", 4)) return DT_IMAGEIO_FILE_CORRUPTED; if(!img->exif_inited) (void)dt_exif_read(img, filename); dt_imageio_png_t image; uint8_t *buf = NULL; uint32_t width, height; uint16_t bpp; if(read_header(filename, &image) != 0) return DT_IMAGEIO_FILE_CORRUPTED; width = img->width = image.width; height = img->height = image.height; bpp = image.bit_depth; img->bpp = 4 * sizeof(float); float *mipbuf = (float *)dt_mipmap_cache_alloc(mbuf, img); if(!mipbuf) { fclose(image.f); png_destroy_read_struct(&image.png_ptr, &image.info_ptr, NULL); fprintf(stderr, "[png_open] could not alloc full buffer for image `%s'\n", img->filename); return DT_IMAGEIO_CACHE_FULL; } buf = dt_alloc_align(16, (size_t)width * height * 3 * (bpp < 16 ? 1 : 2)); if(!buf) { fclose(image.f); png_destroy_read_struct(&image.png_ptr, &image.info_ptr, NULL); fprintf(stderr, "[png_open] could not alloc intermediate buffer for image `%s'\n", img->filename); return DT_IMAGEIO_CACHE_FULL; } if(read_image(&image, (void *)buf) != 0) { dt_free_align(buf); fprintf(stderr, "[png_open] could not read image `%s'\n", img->filename); return DT_IMAGEIO_FILE_CORRUPTED; } for(size_t j = 0; j < height; j++) { if(bpp < 16) for(size_t i = 0; i < width; i++) for(int k = 0; k < 3; k++) mipbuf[4 * (j * width + i) + k] = buf[3 * (j * width + i) + k] * (1.0f / 255.0f); else for(size_t i = 0; i < width; i++) for(int k = 0; k < 3; k++) mipbuf[4 * (j * width + i) + k] = (256.0f * buf[2 * (3 * (j * width + i) + k)] + buf[2 * (3 * (j * width + i) + k) + 1]) * (1.0f / 65535.0f); } dt_free_align(buf); return DT_IMAGEIO_OK; }
dt_imageio_retval_t dt_imageio_open_gm( dt_image_t *img, const char *filename, dt_mipmap_cache_allocator_t a) { int err = DT_IMAGEIO_FILE_CORRUPTED; float *buf = NULL; ExceptionInfo exception; Image *image = NULL; ImageInfo *image_info = NULL; uint32_t width, height, orientation; if(!_supported_image(filename)) return DT_IMAGEIO_FILE_CORRUPTED; if(!img->exif_inited) (void) dt_exif_read(img, filename); GetExceptionInfo(&exception); image_info=CloneImageInfo((ImageInfo *) NULL); g_strlcpy(image_info->filename,filename,sizeof(image_info->filename)); image=ReadImage(image_info,&exception); if (exception.severity != UndefinedException) CatchException(&exception); if (!image) { fprintf(stderr, "[GraphicsMagick_open] image `%s' not found\n", img->filename); err = DT_IMAGEIO_FILE_NOT_FOUND; goto error; } width = image->columns; height = image->rows; orientation = image->orientation; if(orientation & 4) { img->width = height; img->height = width; } else { img->width = width; img->height = height; } img->bpp = 4*sizeof(float); float *mipbuf = (float *)dt_mipmap_cache_alloc(img, DT_MIPMAP_FULL, a); if(!mipbuf) { fprintf(stderr, "[GraphicsMagick_open] could not alloc full buffer for image `%s'\n", img->filename); err = DT_IMAGEIO_CACHE_FULL; goto error; } buf = (float *)dt_alloc_align(16, width*img->bpp); if(!buf) goto error; const int ht2 = orientation & 4 ? img->width : img->height; // pretend unrotated, rotate in write_pos const int wd2 = orientation & 4 ? img->height : img->width; for (uint32_t row = 0; row < height; row++) { int ret = DispatchImage(image, 0, row, width, 1, "RGBP", FloatPixel, (void *)buf, &exception); if (exception.severity != UndefinedException) CatchException(&exception); if(ret != MagickPass) { fprintf(stderr, "[GraphicsMagick_open] error reading image `%s'\n", img->filename); err = DT_IMAGEIO_FILE_CORRUPTED; goto error; } for(uint32_t i=0; i<width; i++) for(int k=0; k<4; k++) mipbuf[4*dt_imageio_write_pos(i, row, wd2, ht2, wd2, ht2, orientation) + k] = buf[4*i + k]; } if(buf) dt_free_align(buf); if(image) DestroyImage(image); if(image_info) DestroyImageInfo(image_info); DestroyExceptionInfo(&exception); img->filters = 0; img->flags &= ~DT_IMAGE_RAW; img->flags &= ~DT_IMAGE_HDR; img->flags |= DT_IMAGE_LDR; return DT_IMAGEIO_OK; error: if(buf) dt_free_align(buf); if(image) DestroyImage(image); if(image_info) DestroyImageInfo(image_info); DestroyExceptionInfo(&exception); return err; }
dt_imageio_retval_t dt_imageio_open_j2k(dt_image_t *img, const char *filename, dt_mipmap_cache_allocator_t a) { opj_dparameters_t parameters; /* decompression parameters */ opj_event_mgr_t event_mgr; /* event manager */ opj_image_t *image = NULL; FILE *fsrc = NULL; unsigned char *src = NULL; int file_length; opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ opj_cio_t *cio = NULL; OPJ_CODEC_FORMAT codec; int ret = DT_IMAGEIO_FILE_CORRUPTED; int file_format = get_file_format(filename); if(file_format == -1) return DT_IMAGEIO_FILE_CORRUPTED; if(!img->exif_inited) (void) dt_exif_read(img, filename); /* read the input file and put it in memory */ /* ---------------------------------------- */ fsrc = fopen(filename, "rb"); if(!fsrc) { fprintf(stderr, "[j2k_open] Error: failed to open `%s' for reading\n", filename); return DT_IMAGEIO_FILE_NOT_FOUND; } fseek(fsrc, 0, SEEK_END); file_length = ftell(fsrc); fseek(fsrc, 0, SEEK_SET); src = (unsigned char *) malloc(file_length); if(fread(src, 1, file_length, fsrc) != (size_t)file_length) { free(src); fclose(fsrc); fprintf(stderr, "[j2k_open] Error: fread returned a number of elements different from the expected.\n"); return DT_IMAGEIO_FILE_NOT_FOUND; } fclose(fsrc); if(memcmp(JP2_HEAD, src, sizeof(JP2_HEAD)) == 0) { file_format = JP2_CFMT; // just in case someone used the wrong extension } else if(memcmp(J2K_HEAD, src, sizeof(J2K_HEAD)) == 0) { file_format = J2K_CFMT; // just in case someone used the wrong extension } else // this will also reject jpt files. { free(src); fprintf(stderr, "[j2k_open] Error: `%s' has unsupported file format.\n", filename); return DT_IMAGEIO_FILE_CORRUPTED; } /* configure the event callbacks (not required) */ memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); event_mgr.error_handler = error_callback; // event_mgr.warning_handler = warning_callback; // event_mgr.info_handler = info_callback; /* set decoding parameters to default values */ opj_set_default_decoder_parameters(¶meters); /* decode the code-stream */ /* ---------------------- */ if(file_format == J2K_CFMT) /* JPEG-2000 codestream */ codec = CODEC_J2K; else if(file_format == JP2_CFMT) /* JPEG 2000 compressed image data */ codec = CODEC_JP2; else if(file_format == JPT_CFMT) /* JPEG 2000, JPIP */ codec = CODEC_JPT; else { free(src); return DT_IMAGEIO_FILE_CORRUPTED; // can't happen } /* get a decoder handle */ dinfo = opj_create_decompress(codec); /* catch events using our callbacks and give a local context */ opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr); /* setup the decoder decoding parameters using user parameters */ opj_setup_decoder(dinfo, ¶meters); /* open a byte stream */ cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); /* decode the stream and fill the image structure */ image = opj_decode(dinfo, cio); /* close the byte stream */ opj_cio_close(cio); /* free the memory containing the code-stream */ free(src); if(!image) { fprintf(stderr, "[j2k_open] Error: failed to decode image `%s'\n", filename); ret = DT_IMAGEIO_FILE_CORRUPTED; goto end_of_the_world; } if(image->color_space == CLRSPC_SYCC) { color_sycc_to_rgb(image); } //FIXME: openjpeg didn't have support for icc profiles before version 1.5 // this needs some #ifdef magic and proper implementation #ifdef HAVE_OPENJPEG_ICC if(image->icc_profile_buf) { #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) color_apply_icc_profile(image); #endif free(image->icc_profile_buf); image->icc_profile_buf = NULL; image->icc_profile_len = 0; } #endif /* create output image */ /* ------------------- */ long signed_offsets[4] = {0, 0, 0, 0}; int float_divs[4] = {1, 1, 1, 1}; // some sanity checks if(image->numcomps == 0 || image->x1 == 0 || image->y1 == 0) { fprintf(stderr, "[j2k_open] Error: invalid raw image parameters in `%s'\n", filename); ret = DT_IMAGEIO_FILE_CORRUPTED; goto end_of_the_world; } for(int i = 0; i < image->numcomps; i++) { if(image->comps[i].w != image->x1 || image->comps[i].h != image->y1) { fprintf(stderr, "[j2k_open] Error: some component has different size in `%s'\n", filename); ret = DT_IMAGEIO_FILE_CORRUPTED; goto end_of_the_world; } if(image->comps[i].prec > 16) { fprintf(stderr,"[j2k_open] Error: precision %d is larger than 16 in `%s'\n", image->comps[1].prec, filename); ret = DT_IMAGEIO_FILE_CORRUPTED; goto end_of_the_world; } } img->width = image->x1; img->height = image->y1; img->bpp = 4*sizeof(float); float *buf = (float *)dt_mipmap_cache_alloc(img, DT_MIPMAP_FULL, a); if(!buf) { ret = DT_IMAGEIO_CACHE_FULL; goto end_of_the_world; } int i = image->numcomps; if(i > 4) i = 4; while(i) { i--; if(image->comps[i].sgnd) signed_offsets[i] = 1 << (image->comps[i].prec - 1); float_divs[i] = (1 << image->comps[i].prec) - 1; } // numcomps == 1 : grey -> r = grey, g = grey, b = grey // numcomps == 2 : grey, alpha -> r = grey, g = grey, b = grey. put alpha into the mix? // numcomps == 3 : rgb -> rgb // numcomps == 4 : rgb, alpha -> rgb. put alpha into the mix? // first try: ignore alpha. if(image->numcomps < 3) // 1, 2 => grayscale { for(int i = 0; i < img->width * img->height; i++) buf[i*4 + 0] = buf[i*4 + 1] = buf[i*4 + 2] = (float)(image->comps[0].data[i] + signed_offsets[0]) / float_divs[0]; } else // 3, 4 => rgb { for(int i = 0; i < img->width * img->height; i++) for(int k = 0; k < 3; k++) buf[i*4 + k] = (float)(image->comps[k].data[i] + signed_offsets[k]) / float_divs[k]; } ret = DT_IMAGEIO_OK; end_of_the_world: /* free remaining structures */ if(dinfo) opj_destroy_decompress(dinfo); /* free image data structure */ opj_image_destroy(image); return ret; }
dt_imageio_retval_t dt_imageio_open_tiff(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf) { // doing this once would be enough, but our imageio reading code is // compiled into dt's core and doesn't have an init routine. TIFFSetWarningHandler(_warning_handler); TIFFSetErrorHandler(_error_handler); const char *ext = filename + strlen(filename); while(*ext != '.' && ext > filename) ext--; if(strncmp(ext, ".tif", 4) && strncmp(ext, ".TIF", 4) && strncmp(ext, ".tiff", 5) && strncmp(ext, ".TIFF", 5)) return DT_IMAGEIO_FILE_CORRUPTED; if(!img->exif_inited) (void)dt_exif_read(img, filename); tiff_t t; uint16_t config; t.image = img; if((t.tiff = TIFFOpen(filename, "rb")) == NULL) return DT_IMAGEIO_FILE_CORRUPTED; TIFFGetField(t.tiff, TIFFTAG_IMAGEWIDTH, &t.width); TIFFGetField(t.tiff, TIFFTAG_IMAGELENGTH, &t.height); TIFFGetField(t.tiff, TIFFTAG_BITSPERSAMPLE, &t.bpp); TIFFGetField(t.tiff, TIFFTAG_SAMPLESPERPIXEL, &t.spp); TIFFGetFieldDefaulted(t.tiff, TIFFTAG_SAMPLEFORMAT, &t.sampleformat); TIFFGetField(t.tiff, TIFFTAG_PLANARCONFIG, &config); if(TIFFRasterScanlineSize(t.tiff) != TIFFScanlineSize(t.tiff)) return DT_IMAGEIO_FILE_CORRUPTED; t.scanlinesize = TIFFScanlineSize(t.tiff); dt_print(DT_DEBUG_CAMERA_SUPPORT, "[tiff_open] %dx%d %dbpp, %d samples per pixel.\n", t.width, t.height, t.bpp, t.spp); // we only support 8/16 and 32 bits per pixel formats. if(t.bpp != 8 && t.bpp != 16 && t.bpp != 32) { TIFFClose(t.tiff); return DT_IMAGEIO_FILE_CORRUPTED; } /* we only support 1,3 or 4 samples per pixel */ if(t.spp != 1 && t.spp != 3 && t.spp != 4) { TIFFClose(t.tiff); return DT_IMAGEIO_FILE_CORRUPTED; } /* initialize cached image buffer */ t.image->width = t.width; t.image->height = t.height; t.image->buf_dsc.channels = 4; t.image->buf_dsc.datatype = TYPE_FLOAT; t.mipbuf = (float *)dt_mipmap_cache_alloc(mbuf, t.image); if(!t.mipbuf) { fprintf(stderr, "[tiff_open] error: could not alloc full buffer for image `%s'\n", t.image->filename); TIFFClose(t.tiff); return DT_IMAGEIO_CACHE_FULL; } /* dont depend on planar config if spp == 1 */ if(t.spp > 1 && config != PLANARCONFIG_CONTIG) { fprintf(stderr, "[tiff_open] error: planar config other than contig is not supported.\n"); TIFFClose(t.tiff); return DT_IMAGEIO_FILE_CORRUPTED; } if((t.buf = _TIFFmalloc(t.scanlinesize)) == NULL) { TIFFClose(t.tiff); return DT_IMAGEIO_CACHE_FULL; } int ok = 1; if(t.bpp == 8 && t.sampleformat == SAMPLEFORMAT_UINT && config == PLANARCONFIG_CONTIG) ok = _read_planar_8(&t); else if(t.bpp == 16 && t.sampleformat == SAMPLEFORMAT_UINT && config == PLANARCONFIG_CONTIG) ok = _read_planar_16(&t); else if(t.bpp == 32 && t.sampleformat == SAMPLEFORMAT_IEEEFP && config == PLANARCONFIG_CONTIG) ok = _read_planar_f(&t); else { fprintf(stderr, "[tiff_open] error: Not a supported tiff image format."); ok = 0; } _TIFFfree(t.buf); TIFFClose(t.tiff); return (ok == 1 ? DT_IMAGEIO_OK : DT_IMAGEIO_FILE_CORRUPTED); }