void dt_control_job_set_params(_dt_job_t *job, void *params, dt_job_destroy_callback callback) { if(!job || dt_control_job_get_state(job) != DT_JOB_STATE_INITIALIZED) return; job->params = params; job->params_size = 0; job->params_destroy = callback; }
void dt_control_job_set_state_callback(_dt_job_t *job, dt_job_state_change_callback cb) { // once the job got added to the queue it may not be changed from the outside if(dt_control_job_get_state(job) != DT_JOB_STATE_INITIALIZED) return; // get_state returns DISPOSED when job == NULL job->state_changed_cb = cb; }
int32_t dt_control_run_job_res(dt_control_t *s, int32_t res) { assert(res < DT_CTL_WORKER_RESERVED && res >= 0); dt_job_t *j = NULL; dt_pthread_mutex_lock(&s->queue_mutex); if(s->new_res[res]) j = s->job_res + res; s->new_res[res] = 0; dt_pthread_mutex_unlock(&s->queue_mutex); if(!j) return -1; /* change state to running */ dt_pthread_mutex_lock (&j->wait_mutex); if (dt_control_job_get_state (j) == DT_JOB_STATE_QUEUED) { dt_print(DT_DEBUG_CONTROL, "[run_job+] %02d %f ", res, dt_get_wtime()); dt_control_job_print(j); dt_print(DT_DEBUG_CONTROL, "\n"); _control_job_set_state (j,DT_JOB_STATE_RUNNING); /* execute job */ j->result = j->execute (j); _control_job_set_state (j,DT_JOB_STATE_FINISHED); dt_print(DT_DEBUG_CONTROL, "[run_job-] %02d %f ", res, dt_get_wtime()); dt_control_job_print(j); dt_print(DT_DEBUG_CONTROL, "\n"); } dt_pthread_mutex_unlock (&j->wait_mutex); return 0; }
static int32_t dt_control_run_job(dt_control_t *control) { _dt_job_t *job = dt_control_schedule_job(control); if(!job) return -1; /* change state to running */ dt_pthread_mutex_lock(&job->wait_mutex); if(dt_control_job_get_state(job) == DT_JOB_STATE_QUEUED) { dt_print(DT_DEBUG_CONTROL, "[run_job+] %02d %f ", DT_CTL_WORKER_RESERVED + dt_control_get_threadid(), dt_get_wtime()); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); dt_control_job_set_state(job, DT_JOB_STATE_RUNNING); /* execute job */ job->result = job->execute(job); dt_control_job_set_state(job, DT_JOB_STATE_FINISHED); dt_print(DT_DEBUG_CONTROL, "[run_job-] %02d %f ", DT_CTL_WORKER_RESERVED + dt_control_get_threadid(), dt_get_wtime()); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); } /* free job */ dt_pthread_mutex_unlock(&job->wait_mutex); dt_control_job_dispose(job); return 0; }
void dt_control_job_wait(_dt_job_t *job) { if(!job) return; dt_job_state_t state = dt_control_job_get_state(job); /* if job execution is not finished let's wait for signal */ if(state == DT_JOB_STATE_RUNNING || state == DT_JOB_STATE_CANCELLED) { dt_pthread_mutex_lock(&job->wait_mutex); dt_pthread_mutex_unlock(&job->wait_mutex); } }
void dt_control_job_wait(dt_job_t *j) { int state = dt_control_job_get_state (j); /* if job execution not is finished let's wait for signal */ if (state==DT_JOB_STATE_RUNNING || state==DT_JOB_STATE_CANCELLED) { dt_pthread_mutex_lock (&j->wait_mutex); dt_pthread_mutex_unlock (&j->wait_mutex); } }
int32_t dt_control_local_copy_images_job_run(dt_job_t *job) { int imgid = -1; dt_control_image_enumerator_t *t1 = (dt_control_image_enumerator_t *)job->param; GList *t = t1->index; guint tagid = 0; const int total = g_list_length(t); double fraction=0; gboolean is_copy = GPOINTER_TO_INT(job->user_data) == 1; char message[512]= {0}; if (is_copy) snprintf(message, 512, ngettext ("creating local copy of %d image", "creating local copies of %d images", total), total); else snprintf(message, 512, ngettext ("removing local copy of %d image", "removing local copies of %d images", total), total); dt_control_log(message); dt_tag_new("darktable|local-copy",&tagid); /* create a cancellable bgjob ui template */ const guint *jid = dt_control_backgroundjobs_create(darktable.control, 0, message); dt_control_backgroundjobs_set_cancellable(darktable.control, jid, job); const dt_control_t *control = darktable.control; while(t && dt_control_job_get_state(job) != DT_JOB_STATE_CANCELLED) { imgid = GPOINTER_TO_INT(t->data); if (GPOINTER_TO_INT(job->user_data) == 1) { dt_image_local_copy_set(imgid); dt_tag_attach(tagid, imgid); } else { dt_image_local_copy_reset(imgid); dt_tag_detach(tagid, imgid); } t = g_list_delete_link(t, t); fraction += 1.0/total; dt_control_backgroundjobs_progress(control, jid, fraction); } dt_control_backgroundjobs_destroy(control, jid); dt_control_signal_raise(darktable.signals, DT_SIGNAL_FILMROLLS_CHANGED); return 0; }
static int32_t _generic_dt_control_fileop_images_job_run(dt_job_t *job, int32_t (*fileop_callback)(const int32_t, const int32_t), const char *desc, const char *desc_pl) { dt_control_image_enumerator_t *t1 = (dt_control_image_enumerator_t *)job->param; GList *t = t1->index; int total = g_list_length(t); char message[512]= {0}; double fraction = 0; gchar *newdir = (gchar *)job->user_data; /* create a cancellable bgjob ui template */ g_snprintf(message, 512, ngettext(desc, desc_pl, total), total); const guint *jid = dt_control_backgroundjobs_create(darktable.control, 0, message); dt_control_backgroundjobs_set_cancellable(darktable.control, jid, job); // create new film roll for the destination directory dt_film_t new_film; const int32_t film_id = dt_film_new(&new_film, newdir); g_free(newdir); if (film_id <= 0) { dt_control_log(_("failed to create film roll for destination directory, aborting move..")); dt_control_backgroundjobs_destroy(darktable.control, jid); return -1; } while(t && dt_control_job_get_state(job) != DT_JOB_STATE_CANCELLED) { fileop_callback(GPOINTER_TO_INT(t->data), film_id); t = g_list_delete_link(t, t); fraction+=1.0/total; dt_control_backgroundjobs_progress(darktable.control, jid, fraction); } char collect[1024]; snprintf(collect, 1024, "1:0:0:%s$", new_film.dirname); dt_collection_deserialize(collect); dt_control_backgroundjobs_destroy(darktable.control, jid); dt_film_remove_empty(); dt_control_signal_raise(darktable.signals, DT_SIGNAL_FILMROLLS_CHANGED); dt_control_queue_redraw_center(); return 0; }
static int32_t dt_control_run_job(dt_control_t *control) { _dt_job_t *job = dt_control_schedule_job(control); if(!job) return -1; /* change state to running */ dt_pthread_mutex_lock(&job->wait_mutex); if(dt_control_job_get_state(job) == DT_JOB_STATE_QUEUED) { dt_print(DT_DEBUG_CONTROL, "[run_job+] %02d %f ", DT_CTL_WORKER_RESERVED + dt_control_get_threadid(), dt_get_wtime()); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); dt_control_job_set_state(job, DT_JOB_STATE_RUNNING); /* execute job */ job->result = job->execute(job); dt_control_job_set_state(job, DT_JOB_STATE_FINISHED); dt_print(DT_DEBUG_CONTROL, "[run_job-] %02d %f ", DT_CTL_WORKER_RESERVED + dt_control_get_threadid(), dt_get_wtime()); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); } dt_pthread_mutex_unlock(&job->wait_mutex); // remove the job from scheduled job array (for job deduping) dt_pthread_mutex_lock(&control->queue_mutex); control->job[dt_control_get_threadid()] = NULL; if(job->queue == DT_JOB_QUEUE_USER_EXPORT) control->export_scheduled = FALSE; dt_pthread_mutex_unlock(&control->queue_mutex); // and free it dt_control_job_dispose(job); return 0; }
static int32_t dt_control_run_job_res(dt_control_t *control, int32_t res) { if(((unsigned int)res) >= DT_CTL_WORKER_RESERVED) return -1; _dt_job_t *job = NULL; dt_pthread_mutex_lock(&control->queue_mutex); if(control->new_res[res]) { job = control->job_res[res]; control->job_res[res] = NULL; // this job belongs to us now, the queue may not touch it any longer } control->new_res[res] = 0; dt_pthread_mutex_unlock(&control->queue_mutex); if(!job) return -1; /* change state to running */ dt_pthread_mutex_lock(&job->wait_mutex); if(dt_control_job_get_state(job) == DT_JOB_STATE_QUEUED) { dt_print(DT_DEBUG_CONTROL, "[run_job+] %02d %f ", res, dt_get_wtime()); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); dt_control_job_set_state(job, DT_JOB_STATE_RUNNING); /* execute job */ job->result = job->execute(job); dt_control_job_set_state(job, DT_JOB_STATE_FINISHED); dt_print(DT_DEBUG_CONTROL, "[run_job-] %02d %f ", res, dt_get_wtime()); dt_control_job_print(job); dt_print(DT_DEBUG_CONTROL, "\n"); } dt_pthread_mutex_unlock(&job->wait_mutex); dt_control_job_dispose(job); return 0; }
static int32_t dt_control_run_job(dt_control_t *control) { _dt_job_t *job = dt_control_schedule_job(control); if(!job) return -1; /* change state to running */ dt_pthread_mutex_lock(&job->wait_mutex); if(dt_control_job_get_state(job) == DT_JOB_STATE_QUEUED) dt_control_job_execute(job); dt_pthread_mutex_unlock(&job->wait_mutex); // remove the job from scheduled job array (for job deduping) dt_pthread_mutex_lock(&control->queue_mutex); control->job[dt_control_get_threadid()] = NULL; if(job->queue == DT_JOB_QUEUE_USER_EXPORT) control->export_scheduled = FALSE; dt_pthread_mutex_unlock(&control->queue_mutex); // and free it dt_control_job_dispose(job); return 0; }
int32_t dt_control_run_job(dt_control_t *s) { dt_job_t *j=NULL,*bj=NULL; dt_pthread_mutex_lock(&s->queue_mutex); /* check if queue is empty */ if(g_list_length(s->queue) == 0) { dt_pthread_mutex_unlock(&s->queue_mutex); return -1; } /* go thru the queue and find one normal job and a background job that is up for execution.*/ time_t ts_now = time(NULL); GList *jobitem=g_list_first(s->queue); if(jobitem) do { dt_job_t *tj = jobitem->data; /* check if it's a scheduled job and is waiting to be executed */ if(!bj && (tj->ts_execute > tj->ts_added) && tj->ts_execute <= ts_now) bj = tj; else if ((tj->ts_execute < tj->ts_added) && !j) j = tj; /* if we got a normal job, and a background job, we are finished */ if(bj && j) break; } while ((jobitem = g_list_next(jobitem))); /* remove the found jobs from queue */ if (bj) s->queue = g_list_remove(s->queue, bj); if (j) s->queue = g_list_remove(s->queue, j); /* unlock the queue */ dt_pthread_mutex_unlock(&s->queue_mutex); /* push background job on reserved background worker */ if(bj) { dt_control_add_job_res(s,bj,DT_CTL_WORKER_7); g_free (bj); } /* don't continue if we don't have have a job to execute */ if(!j) return -1; /* change state to running */ dt_pthread_mutex_lock (&j->wait_mutex); if (dt_control_job_get_state (j) == DT_JOB_STATE_QUEUED) { dt_print(DT_DEBUG_CONTROL, "[run_job+] %02d %f ", DT_CTL_WORKER_RESERVED+dt_control_get_threadid(), dt_get_wtime()); dt_control_job_print(j); dt_print(DT_DEBUG_CONTROL, "\n"); _control_job_set_state (j,DT_JOB_STATE_RUNNING); /* execute job */ j->result = j->execute (j); _control_job_set_state (j,DT_JOB_STATE_FINISHED); dt_print(DT_DEBUG_CONTROL, "[run_job-] %02d %f ", DT_CTL_WORKER_RESERVED+dt_control_get_threadid(), dt_get_wtime()); dt_control_job_print(j); dt_print(DT_DEBUG_CONTROL, "\n"); /* free job */ dt_pthread_mutex_unlock (&j->wait_mutex); g_free(j); j = NULL; } if(j) dt_pthread_mutex_unlock (&j->wait_mutex); return 0; }
int _camera_storage_image_filename(const dt_camera_t *camera,const char *filename,CameraFile *preview,CameraFile *exif,void *user_data) { _camera_import_dialog_t *data=(_camera_import_dialog_t*)user_data; GtkTreeIter iter; const char *img; unsigned long size; GdkPixbuf *pixbuf=NULL; GdkPixbuf *thumb=NULL; /* stop fetching previews if job is cancelled */ if (data->preview_job && dt_control_job_get_state(data->preview_job) == DT_JOB_STATE_CANCELLED ) return 0; gboolean i_own_lock = dt_control_gdk_lock(); char exif_info[1024]= {0}; char file_info[4096]= {0}; if( preview ) { gp_file_get_data_and_size(preview, &img, &size); if( size > 0 ) { // we got preview image data lets create a pixbuf from image blob GError *err=NULL; GInputStream *stream; if( (stream = g_memory_input_stream_new_from_data(img, size,NULL)) !=NULL) pixbuf = gdk_pixbuf_new_from_stream( stream, NULL, &err ); } if(pixbuf) { // Scale pixbuf to a thumbnail double sw=gdk_pixbuf_get_width( pixbuf ); double scale=75.0/gdk_pixbuf_get_height( pixbuf ); thumb = gdk_pixbuf_scale_simple( pixbuf, sw*scale,75 , GDK_INTERP_BILINEAR ); } } #if 0 // libgphoto only supports fetching exif in jpegs, not raw char buffer[1024]= {0}; if ( exif ) { const char *exif_data; char *value=NULL; gp_file_get_data_and_size(exif, &exif_data, &size); if( size > 0 ) { void *exif=dt_exif_data_new((uint8_t *)exif_data,size); if( (value=g_strdup( dt_exif_data_get_value(exif,"Exif.Photo.ExposureTime",buffer,1024) ) ) != NULL); snprintf(exif_info, sizeof(exif_info), "exposure: %s\n", value); } else fprintf(stderr,"No exifdata read\n"); } #endif // filename\n 1/60 f/2.8 24mm iso 160 snprintf(file_info, sizeof(file_info), "%s%c%s",filename,strlen(exif_info)?'\n':'\0',strlen(exif_info)?exif_info:""); gtk_list_store_append(data->store,&iter); gtk_list_store_set(data->store,&iter,0,thumb,1,file_info,-1); if(pixbuf) g_object_unref(pixbuf); if(thumb) g_object_ref(thumb); if (i_own_lock) dt_control_gdk_unlock(); return 1; }
int32_t dt_control_indexer_job_run(dt_job_t *job) { // if no indexing was requested, bail out: if(!dt_conf_get_bool("run_similarity_indexer")) return 0; /* * First pass run thru ALL images and collect the ones who needs to update * \TODO in the future lets have a indexer table with ids filed with images * thats need some kind of reindexing.. all mark dirty functions adds image * to this table-- */ // temp memory for uncompressed images: uint8_t *scratchmem = dt_mipmap_cache_alloc_scratchmem(darktable.mipmap_cache); GList *images=NULL; sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select images.id,film_rolls.folder||'/'||images.filename,images.histogram,images.lightmap from images,film_rolls where film_rolls.id = images.film_id", -1, &stmt, NULL); while(sqlite3_step(stmt) == SQLITE_ROW) { _control_indexer_img_t *idximg=g_malloc(sizeof( _control_indexer_img_t)); memset(idximg,0,sizeof(_control_indexer_img_t)); idximg->id = sqlite3_column_int(stmt,0); /* first check if image file exists on disk */ const char *filename = (const char *)sqlite3_column_text(stmt, 1); if (filename && !g_file_test(filename, G_FILE_TEST_IS_REGULAR)) idximg->flags |= _INDEXER_IMAGE_FILE_REMOVED; /* check if histogram should be updated */ if (sqlite3_column_bytes(stmt, 2) != sizeof(dt_similarity_histogram_t)) idximg->flags |= _INDEXER_UPDATE_HISTOGRAM; /* check if lightmap should be updated */ if (sqlite3_column_bytes(stmt, 3) != sizeof(dt_similarity_lightmap_t)) idximg->flags |= _INDEXER_UPDATE_LIGHTMAP; /* if image is flagged add to collection */ if (idximg->flags != 0) images = g_list_append(images, idximg); else g_free(idximg); } sqlite3_finalize(stmt); /* * Second pass, run thru collected images thats * need reindexing... */ GList *imgitem = g_list_first(images); if(imgitem) { char message[512]= {0}; double fraction=0; int total = g_list_length(images); guint *jid = NULL; /* background job plate only if more then one image is reindexed */ if (total > 1) { snprintf(message, 512, ngettext ("re-indexing %d image", "re-indexing %d images", total), total ); jid = (guint *)dt_control_backgroundjobs_create(darktable.control, 0, message); } do { // bail out if we're shutting down: if(!dt_control_running()) break; // if indexer was switched off during runtime, respect that as soon as we can: if(!dt_conf_get_bool("run_similarity_indexer")) break; /* get the _control_indexer_img_t pointer */ _control_indexer_img_t *idximg = imgitem->data; /* * Check if image has been delete from disk */ if ((idximg->flags&_INDEXER_IMAGE_FILE_REMOVED)) { /* file does not exist on disk lets delete image reference from database */ //char query[512]={0}; // \TODO dont delete move to an temp table and let user to revalidate /*sprintf(query,"delete from history where imgid=%d",idximg->id); DT_DEBUG_SQLITE3_EXEC(darktable.db, query, NULL, NULL, NULL); sprintf(query,"delete from tagged_images where imgid=%d",idximg->id); DT_DEBUG_SQLITE3_EXEC(darktable.db, query, NULL, NULL, NULL); sprintf(query,"delete from images where id=%d",idximg->id); DT_DEBUG_SQLITE3_EXEC(darktable.db, query, NULL, NULL, NULL);*/ /* no need to additional work */ continue; } /* * Check if image histogram or lightmap should be updated. * those indexing that involves a image pipe should fall into this */ if ( (idximg->flags&_INDEXER_UPDATE_HISTOGRAM) || (idximg->flags&_INDEXER_UPDATE_LIGHTMAP) ) { /* get a mipmap of image to analyse */ dt_mipmap_buffer_t buf; dt_mipmap_cache_read_get(darktable.mipmap_cache, &buf, idximg->id, DT_MIPMAP_2, DT_MIPMAP_BLOCKING); // pointer owned by the cache or == scratchmem, no need to free this one: uint8_t *buf_decompressed = dt_mipmap_cache_decompress(&buf, scratchmem); if (!(buf.width * buf.height)) continue; /* * Generate similarity histogram data if requested */ if ( (idximg->flags&_INDEXER_UPDATE_HISTOGRAM) ) { dt_similarity_histogram_t histogram; float bucketscale = (float)DT_SIMILARITY_HISTOGRAM_BUCKETS/(float)0xff; for(int j=0; j<(4*buf.width*buf.height); j+=4) { /* swap rgb and scale to bucket index */ uint8_t rgb[3]; for(int k=0; k<3; k++) rgb[k] = (int)((buf_decompressed[j+2-k]/(float)0xff) * bucketscale); /* distribute rgb into buckets */ for(int k=0; k<3; k++) histogram.rgbl[rgb[k]][k]++; /* distribute lum into buckets */ uint8_t lum = MAX(MAX(rgb[0], rgb[1]), rgb[2]); histogram.rgbl[lum][3]++; } for(int k=0; k<DT_SIMILARITY_HISTOGRAM_BUCKETS; k++) for (int j=0; j<4; j++) histogram.rgbl[k][j] /= (buf.width*buf.height); /* store the histogram data */ dt_similarity_histogram_store(idximg->id, &histogram); } /* * Generate scaledowned similarity lightness map if requested */ if ( (idximg->flags&_INDEXER_UPDATE_LIGHTMAP) ) { dt_similarity_lightmap_t lightmap; memset(&lightmap,0,sizeof(dt_similarity_lightmap_t)); /* * create a pixbuf out of the image for downscaling */ /* first of setup a standard rgb buffer, swap bgr in same routine */ uint8_t *rgbbuf = g_malloc(buf.width*buf.height*3); for(int j=0; j<(buf.width*buf.height); j++) for(int k=0; k<3; k++) rgbbuf[3*j+k] = buf_decompressed[4*j+2-k]; /* then create pixbuf and scale down to lightmap size */ GdkPixbuf *source = gdk_pixbuf_new_from_data(rgbbuf,GDK_COLORSPACE_RGB,FALSE,8,buf.width,buf.height,(buf.width*3),NULL,NULL); GdkPixbuf *scaled = gdk_pixbuf_scale_simple(source,DT_SIMILARITY_LIGHTMAP_SIZE,DT_SIMILARITY_LIGHTMAP_SIZE,GDK_INTERP_HYPER); /* copy scaled data into lightmap */ uint8_t min=0xff,max=0; uint8_t *spixels = gdk_pixbuf_get_pixels(scaled); for(int j=0; j<(DT_SIMILARITY_LIGHTMAP_SIZE*DT_SIMILARITY_LIGHTMAP_SIZE); j++) { /* copy rgb */ for(int k=0; k<3; k++) lightmap.pixels[4*j+k] = spixels[3*j+k]; /* average intensity into 4th channel */ lightmap.pixels[4*j+3] = (lightmap.pixels[4*j+0]+ lightmap.pixels[4*j+1]+ lightmap.pixels[4*j+2])/3.0; min = MIN(min, lightmap.pixels[4*j+3]); max = MAX(max, lightmap.pixels[4*j+3]); } /* contrast stretch each channel in lightmap * TODO: do we want this... */ float scale=0; int range = max-min; if(range==0) scale = 1.0; else scale = 0xff/range; for(int j=0; j<(DT_SIMILARITY_LIGHTMAP_SIZE*DT_SIMILARITY_LIGHTMAP_SIZE); j++) { for(int k=0; k<4; k++) lightmap.pixels[4*j+k] = (lightmap.pixels[4*j+k]-min)*scale; } /* free some resources */ g_object_unref(scaled); g_object_unref(source); g_free(rgbbuf); /* store the lightmap */ dt_similarity_lightmap_store(idximg->id, &lightmap); } /* no use for buffer anymore release the mipmap */ dt_mipmap_cache_read_release(darktable.mipmap_cache, &buf); } /* update background progress */ if (jid) { fraction+=1.0/total; dt_control_backgroundjobs_progress(darktable.control, jid, fraction); } } while ((imgitem=g_list_next(imgitem)) && dt_control_job_get_state(job) != DT_JOB_STATE_CANCELLED); /* cleanup */ if (jid) dt_control_backgroundjobs_destroy(darktable.control, jid); } free(scratchmem); /* * Indexing opertions finished, lets reschedule the indexer * unless control is shutting down... */ if(dt_control_running()) dt_control_start_indexer(); return 0; }
static int _camera_storage_image_filename(const dt_camera_t *camera, const char *filename, CameraFile *preview, CameraFile *exif, void *user_data) { _camera_import_dialog_t *data = (_camera_import_dialog_t *)user_data; const char *img; unsigned long size; GdkPixbuf *pixbuf = NULL; GdkPixbuf *thumb = NULL; /* stop fetching previews if job is cancelled */ if(data->preview_job && dt_control_job_get_state(data->preview_job) == DT_JOB_STATE_CANCELLED) return 0; char exif_info[1024] = { 0 }; if(preview) { gp_file_get_data_and_size(preview, &img, &size); if(size > 0) { // we got preview image data lets create a pixbuf from image blob GError *err = NULL; GInputStream *stream; if((stream = g_memory_input_stream_new_from_data(img, size, NULL)) != NULL) pixbuf = gdk_pixbuf_new_from_stream(stream, NULL, &err); } if(pixbuf) { // Scale pixbuf to a thumbnail double sw = gdk_pixbuf_get_width(pixbuf); double scale = 75.0 / gdk_pixbuf_get_height(pixbuf); thumb = gdk_pixbuf_scale_simple(pixbuf, sw * scale, 75, GDK_INTERP_BILINEAR); } } #if 0 // libgphoto only supports fetching exif in jpegs, not raw char buffer[1024]= {0}; if ( exif ) { const char *exif_data; char *value=NULL; gp_file_get_data_and_size(exif, &exif_data, &size); if( size > 0 ) { void *exif=dt_exif_data_new((uint8_t *)exif_data,size); if( (value=g_strdup( dt_exif_data_get_value(exif,"Exif.Photo.ExposureTime",buffer,1024) ) ) != NULL); snprintf(exif_info, sizeof(exif_info), "exposure: %s\n", value); } else fprintf(stderr,"No exifdata read\n"); } #endif _image_filename_t *params = (_image_filename_t *)malloc(sizeof(_image_filename_t)); if(!params) { if(pixbuf) g_object_unref(pixbuf); if(thumb) g_object_unref(thumb); return 0; } // filename\n 1/60 f/2.8 24mm iso 160 params->file_info = g_strdup_printf("%s%c%s", filename, *exif_info ? '\n' : '\0', *exif_info ? exif_info : ""); params->thumb = thumb; params->store = data->store; g_main_context_invoke(NULL, _camera_storage_image_filename_gui_thread, params); if(pixbuf) g_object_unref(pixbuf); return 1; }
void dt_control_job_set_params(_dt_job_t *job, void *params) { if(!job || dt_control_job_get_state(job) != DT_JOB_STATE_INITIALIZED) return; job->params = params; }
int32_t dt_control_export_job_run(dt_job_t *job) { long int imgid = -1; dt_control_image_enumerator_t *t1 = (dt_control_image_enumerator_t *)job->param; dt_control_export_t *settings = (dt_control_export_t*)t1->data; GList *t = t1->index; const int total = g_list_length(t); int size = 0; dt_imageio_module_format_t *mformat = dt_imageio_get_format_by_index(settings->format_index); g_assert(mformat); dt_imageio_module_storage_t *mstorage = dt_imageio_get_storage_by_index(settings->storage_index); g_assert(mstorage); // Get max dimensions... uint32_t w,h,fw,fh,sw,sh; fw=fh=sw=sh=0; mstorage->dimension(mstorage, &sw,&sh); mformat->dimension(mformat, &fw,&fh); if( sw==0 || fw==0) w=sw>fw?sw:fw; else w=sw<fw?sw:fw; if( sh==0 || fh==0) h=sh>fh?sh:fh; else h=sh<fh?sh:fh; // get shared storage param struct (global sequence counter, one picasa connection etc) dt_imageio_module_data_t *sdata = mstorage->get_params(mstorage, &size); if(sdata == NULL) { dt_control_log(_("failed to get parameters from storage module, aborting export..")); g_free(t1->data); return 1; } dt_control_log(ngettext ("exporting %d image..", "exporting %d images..", total), total); char message[512]= {0}; snprintf(message, 512, ngettext ("exporting %d image to %s", "exporting %d images to %s", total), total, mstorage->name() ); /* create a cancellable bgjob ui template */ const guint *jid = dt_control_backgroundjobs_create(darktable.control, 0, message ); dt_control_backgroundjobs_set_cancellable(darktable.control, jid, job); const dt_control_t *control = darktable.control; double fraction=0; #ifdef _OPENMP // limit this to num threads = num full buffers - 1 (keep one for darkroom mode) // use min of user request and mipmap cache entries const int full_entries = dt_conf_get_int ("parallel_export"); // GCC won't accept that this variable is used in a macro, considers // it set but not used, which makes for instance Fedora break. const __attribute__((__unused__)) int num_threads = MAX(1, MIN(full_entries, 8)); #if !defined(__SUNOS__) && !defined(__NetBSD__) #pragma omp parallel default(none) private(imgid, size) shared(control, fraction, w, h, stderr, mformat, mstorage, t, sdata, job, jid, darktable, settings) num_threads(num_threads) if(num_threads > 1) #else #pragma omp parallel private(imgid, size) shared(control, fraction, w, h, mformat, mstorage, t, sdata, job, jid, darktable, settings) num_threads(num_threads) if(num_threads > 1) #endif { #endif // get a thread-safe fdata struct (one jpeg struct per thread etc): dt_imageio_module_data_t *fdata = mformat->get_params(mformat, &size); fdata->max_width = settings->max_width; fdata->max_height = settings->max_height; fdata->max_width = (w!=0 && fdata->max_width >w)?w:fdata->max_width; fdata->max_height = (h!=0 && fdata->max_height >h)?h:fdata->max_height; strcpy(fdata->style,settings->style); int num = 0; // Invariant: the tagid for 'darktable|changed' will not change while this function runs. Is this a sensible assumption? guint tagid = 0, etagid = 0; dt_tag_new("darktable|changed",&tagid); dt_tag_new("darktable|exported",&etagid); while(t && dt_control_job_get_state(job) != DT_JOB_STATE_CANCELLED) { #ifdef _OPENMP #pragma omp critical #endif { if(!t) imgid = 0; else { imgid = (long int)t->data; t = g_list_delete_link(t, t); num = total - g_list_length(t); } } // remove 'changed' tag from image dt_tag_detach(tagid, imgid); // make sure the 'exported' tag is set on the image dt_tag_attach(etagid, imgid); // check if image still exists: char imgfilename[DT_MAX_PATH_LEN]; const dt_image_t *image = dt_image_cache_read_get(darktable.image_cache, (int32_t)imgid); if(image) { dt_image_full_path(image->id, imgfilename, DT_MAX_PATH_LEN); if(!g_file_test(imgfilename, G_FILE_TEST_IS_REGULAR)) { dt_control_log(_("image `%s' is currently unavailable"), image->filename); fprintf(stderr, _("image `%s' is currently unavailable"), imgfilename); // dt_image_remove(imgid); dt_image_cache_read_release(darktable.image_cache, image); } else { dt_image_cache_read_release(darktable.image_cache, image); mstorage->store(sdata, imgid, mformat, fdata, num, total, settings->high_quality); } } #ifdef _OPENMP #pragma omp critical #endif { fraction+=1.0/total; dt_control_backgroundjobs_progress(control, jid, fraction); } } #ifdef _OPENMP #pragma omp barrier #pragma omp master #endif { dt_control_backgroundjobs_destroy(control, jid); if(mstorage->finalize_store) mstorage->finalize_store(mstorage, sdata); mstorage->free_params(mstorage, sdata); } // all threads free their fdata mformat->free_params (mformat, fdata); #ifdef _OPENMP } #endif g_free(t1->data); return 0; }