// 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; }
uint32_t dt_image_import(const int32_t film_id, const char *filename, gboolean override_ignore_jpegs) { if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) return 0; const char *cc = filename + strlen(filename); for(; *cc!='.'&&cc>filename; cc--); if(!strcmp(cc, ".dt")) return 0; if(!strcmp(cc, ".dttags")) return 0; if(!strcmp(cc, ".xmp")) return 0; char *ext = g_ascii_strdown(cc+1, -1); if(override_ignore_jpegs == FALSE && (!strcmp(ext, "jpg") || !strcmp(ext, "jpeg")) && dt_conf_get_bool("ui_last/import_ignore_jpegs")) return 0; int supported = 0; char **extensions = g_strsplit(dt_supported_extensions, ",", 100); for(char **i=extensions; *i!=NULL; i++) if(!strcmp(ext, *i)) { supported = 1; break; } g_strfreev(extensions); if(!supported) { g_free(ext); return 0; } int rc; uint32_t id = 0; // select from images; if found => return gchar *imgfname; imgfname = g_path_get_basename((const gchar*)filename); sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select id from images where film_id = ?1 and filename = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, film_id); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, imgfname, strlen(imgfname), SQLITE_STATIC); if(sqlite3_step(stmt) == SQLITE_ROW) { id = sqlite3_column_int(stmt, 0); g_free(imgfname); sqlite3_finalize(stmt); g_free(ext); return id; } sqlite3_finalize(stmt); // also need to set the no-legacy bit, to make sure we get the right presets (new ones) uint32_t flags = dt_conf_get_int("ui_last/import_initial_rating"); if(flags > 5) { flags = 1; dt_conf_set_int("ui_last/import_initial_rating", 1); } flags |= DT_IMAGE_NO_LEGACY_PRESETS; // insert dummy image entry in database DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into images (id, film_id, filename, caption, description, " "license, sha1sum, flags) values (null, ?1, ?2, '', '', '', '', ?3)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, film_id); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, imgfname, strlen(imgfname), SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, flags); rc = sqlite3_step(stmt); if (rc != SQLITE_DONE) fprintf(stderr, "sqlite3 error %d\n", rc); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select id from images where film_id = ?1 and filename = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, film_id); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, imgfname, strlen(imgfname), SQLITE_STATIC); if(sqlite3_step(stmt) == SQLITE_ROW) id = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); // Try to find out if this should be grouped already. gchar *basename = g_strdup(imgfname); gchar *cc2 = basename + strlen(basename); for(; *cc2!='.'&&cc2>basename; cc2--); *cc2='\0'; gchar *sql_pattern = g_strconcat(basename, ".%", NULL); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select group_id from images where film_id = ?1 and filename like ?2 and id != ?3", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, film_id); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, sql_pattern, -1, SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, id); int group_id; if(sqlite3_step(stmt) == SQLITE_ROW) group_id = sqlite3_column_int(stmt, 0); else group_id = id; sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "update images set group_id = ?1 where id = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, group_id); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, id); sqlite3_step(stmt); sqlite3_finalize(stmt); // printf("[image_import] importing `%s' to img id %d\n", imgfname, id); // lock as shortly as possible: const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, id); dt_image_t *img = dt_image_cache_write_get(darktable.image_cache, cimg); img->group_id = group_id; // read dttags and exif for database queries! (void) dt_exif_read(img, filename); char dtfilename[DT_MAX_PATH_LEN]; g_strlcpy(dtfilename, filename, DT_MAX_PATH_LEN); dt_image_path_append_version(id, dtfilename, DT_MAX_PATH_LEN); char *c = dtfilename + strlen(dtfilename); sprintf(c, ".xmp"); (void)dt_exif_xmp_read(img, dtfilename, 0); // write through to db, but not to xmp. dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); dt_image_cache_read_release(darktable.image_cache, img); // add a tag with the file extension guint tagid = 0; char tagname[512]; snprintf(tagname, 512, "darktable|format|%s", ext); g_free(ext); dt_tag_new(tagname, &tagid); dt_tag_attach(tagid,id); // Search for sidecar files and import them if found. glob_t *globbuf = g_malloc(sizeof(glob_t)); // Add version wildcard gchar *fname = g_strdup(filename); gchar pattern[DT_MAX_PATH_LEN]; g_snprintf(pattern, DT_MAX_PATH_LEN, "%s", filename); char *c1 = pattern + strlen(pattern); while(*c1 != '.' && c1 > pattern) c1--; snprintf(c1, pattern + DT_MAX_PATH_LEN - c1, "_*"); char *c2 = fname + strlen(fname); while(*c2 != '.' && c2 > fname) c2--; snprintf(c1+2, pattern + DT_MAX_PATH_LEN - c1 - 2, "%s.xmp", c2); if (!glob(pattern, 0, NULL, globbuf)) { for (int i=0; i < globbuf->gl_pathc; i++) { int newid = -1; newid = dt_image_duplicate(id); const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, newid); dt_image_t *img = dt_image_cache_write_get(darktable.image_cache, cimg); (void)dt_exif_xmp_read(img, globbuf->gl_pathv[i], 0); dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); dt_image_cache_read_release(darktable.image_cache, img); } globfree(globbuf); } g_free(imgfname); g_free(fname); g_free(basename); g_free(sql_pattern); g_free(globbuf); dt_control_signal_raise(darktable.signals,DT_SIGNAL_IMAGE_IMPORT,id); return id; }
// 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_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; }
// maybe this should be (partly) in common/imageio.[c|h]? static void _lib_import_update_preview(GtkFileChooser *file_chooser, gpointer data) { GtkWidget *preview; char *filename; GdkPixbuf *pixbuf = NULL; gboolean have_preview = FALSE, no_preview_fallback = FALSE; preview = GTK_WIDGET(data); filename = gtk_file_chooser_get_preview_filename(file_chooser); if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { no_preview_fallback = TRUE; } else { // don't create dng thumbnails to avoid crashes in libtiff when these are hdr: char *c = filename + strlen(filename); while(c > filename && *c != '.') c--; if(!strcasecmp(c, ".dng")) no_preview_fallback = TRUE; } // unfortunately we can not use following, because frequently it uses wrong orientation // pixbuf = gdk_pixbuf_new_from_file_at_size(filename, 128, 128, NULL); have_preview = (pixbuf != NULL); if(!have_preview && !no_preview_fallback) { uint8_t *buffer = NULL; size_t size; char *mime_type = NULL; if(!dt_exif_get_thumbnail(filename, &buffer, &size, &mime_type)) { // Scale the image to the correct size GdkPixbuf *tmp; GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); if (!gdk_pixbuf_loader_write(loader, buffer, size, NULL)) goto cleanup; if (!(tmp = gdk_pixbuf_loader_get_pixbuf(loader))) goto cleanup; float ratio = 1.0 * gdk_pixbuf_get_height(tmp) / gdk_pixbuf_get_width(tmp); int width = 128, height = 128 * ratio; pixbuf = gdk_pixbuf_scale_simple(tmp, width, height, GDK_INTERP_BILINEAR); have_preview = TRUE; cleanup: gdk_pixbuf_loader_close(loader, NULL); free(mime_type); free(buffer); g_object_unref(loader); // This should clean up tmp as well } } if(have_preview && !no_preview_fallback) { // get image orientation dt_image_t img = { 0 }; (void)dt_exif_read(&img, filename); // Rotate the image to the correct orientation GdkPixbuf *tmp = pixbuf; if(img.orientation == ORIENTATION_ROTATE_CCW_90_DEG) { tmp = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE); } else if(img.orientation == ORIENTATION_ROTATE_CW_90_DEG) { tmp = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE); } else if(img.orientation == ORIENTATION_ROTATE_180_DEG) { tmp = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_UPSIDEDOWN); } if(pixbuf != tmp) { g_object_unref(pixbuf); pixbuf = tmp; } } if(no_preview_fallback || !have_preview) { guint8 *image_buffer = NULL; /* load the dt logo as a brackground */ char filename[PATH_MAX] = { 0 }; char datadir[PATH_MAX] = { 0 }; char *logo; dt_logo_season_t season = get_logo_season(); if(season != DT_LOGO_SEASON_NONE) logo = g_strdup_printf("%%s/pixmaps/idbutton-%d.svg", (int)season); else logo = g_strdup("%s/pixmaps/idbutton.svg"); dt_loc_get_datadir(datadir, sizeof(datadir)); snprintf(filename, sizeof(filename), logo, datadir); g_free(logo); RsvgHandle *svg = rsvg_handle_new_from_file(filename, NULL); if(svg) { cairo_surface_t *surface; cairo_t *cr; RsvgDimensionData dimension; rsvg_handle_get_dimensions(svg, &dimension); float svg_size = MAX(dimension.width, dimension.height); float final_size = 128; float factor = final_size / svg_size; float final_width = dimension.width * factor * darktable.gui->ppd, final_height = dimension.height * factor * darktable.gui->ppd; int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, final_width); image_buffer = (guint8 *)calloc(stride * final_height, sizeof(guint8)); surface = dt_cairo_image_surface_create_for_data(image_buffer, CAIRO_FORMAT_ARGB32, final_width, final_height, stride); if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { free(image_buffer); image_buffer = NULL; } else { cr = cairo_create(surface); cairo_scale(cr, factor, factor); rsvg_handle_render_cairo(svg, cr); cairo_surface_flush(surface); pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, final_width / darktable.gui->ppd, final_height / darktable.gui->ppd); } g_object_unref(svg); } have_preview = TRUE; } if(have_preview) gtk_image_set_from_pixbuf(GTK_IMAGE(preview), pixbuf); if(pixbuf) g_object_unref(pixbuf); g_free(filename); gtk_file_chooser_set_preview_widget_active(file_chooser, have_preview); }
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); }