Esempio n. 1
0
static gboolean
star_key_accel_callback(GtkAccelGroup *accel_group, GObject *acceleratable,
                        guint keyval, GdkModifierType modifier, gpointer data)
{
  long int num = (long int)data;
  switch (num)
  {
    case DT_VIEW_REJECT:
    case DT_VIEW_DESERT:
    case DT_VIEW_STAR_1:
    case DT_VIEW_STAR_2:
    case DT_VIEW_STAR_3:
    case DT_VIEW_STAR_4:
    case DT_VIEW_STAR_5:
    case 666:
    {
      int32_t mouse_over_id;
      DT_CTL_GET_GLOBAL(mouse_over_id, lib_image_mouse_over_id);
      if(mouse_over_id <= 0)
      {
        sqlite3_stmt *stmt;
        DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select imgid from selected_images", -1, &stmt, NULL);
        while(sqlite3_step(stmt) == SQLITE_ROW)
        {
          const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, sqlite3_column_int(stmt, 0));
          dt_image_t *image = dt_image_cache_write_get(darktable.image_cache, cimg);
          if(num == 666 || num == DT_VIEW_DESERT) image->flags &= ~0xf;
          else if(num == DT_VIEW_STAR_1 && ((image->flags & 0x7) == 1)) image->flags &= ~0x7;
          else
          {
            image->flags &= ~0x7;
            image->flags |= num;
          }
          dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_SAFE);
          dt_image_cache_read_release(darktable.image_cache, cimg);
        }
        sqlite3_finalize(stmt);
      }
      else
      {
        const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, mouse_over_id);
        dt_image_t *image = dt_image_cache_write_get(darktable.image_cache, cimg);
        if(num == 666 || num == DT_VIEW_DESERT) image->flags &= ~0xf;
        else if(num == DT_VIEW_STAR_1 && ((image->flags & 0x7) == 1)) image->flags &= ~0x7;
        else
        {
          image->flags &= ~0x7;
          image->flags |= num;
        }
        dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_SAFE);
        dt_image_cache_read_release(darktable.image_cache, cimg);
      }
      dt_control_queue_redraw_center();
      break;
    }
    default:
      break;
  }
  return TRUE;
}
Esempio n. 2
0
static void
drag_and_drop_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data,
                       guint target_type, guint time, gpointer data)
{
  dt_view_t *self = (dt_view_t*)data;
  dt_map_t *lib = (dt_map_t*)self->data;

  gboolean success = FALSE;

  if((selection_data != NULL) && (selection_data->length >= 0) && target_type == DND_TARGET_IMGID)
  {
    float longitude, latitude;
    int *imgid = (int*)selection_data->data;
    if(imgid > 0)
    {
      OsmGpsMapPoint *pt = osm_gps_map_point_new_degrees(0.0, 0.0);
      osm_gps_map_convert_screen_to_geographic(lib->map, x, y, pt);
      osm_gps_map_point_get_degrees(pt, &latitude, &longitude);
      osm_gps_map_point_free(pt);

      const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, *imgid);
      dt_image_t *img = dt_image_cache_write_get(darktable.image_cache, cimg);
      img->longitude = longitude;
      img->latitude = latitude;
      dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_SAFE);
      dt_image_cache_read_release(darktable.image_cache, cimg);

      success = TRUE;
    }
  }
  gtk_drag_finish(context, success, FALSE, time);
}
Esempio n. 3
0
int
dt_history_load_and_apply_on_selection (gchar *filename)
{
  int res=0;
  sqlite3_stmt *stmt;
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select * from selected_images", -1, &stmt, NULL);
  while(sqlite3_step(stmt) == SQLITE_ROW)
  {
    int imgid = sqlite3_column_int(stmt, 0);
    const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, (int32_t)imgid);
    dt_image_t *img = dt_image_cache_write_get(darktable.image_cache, cimg);
    if(img)
    {
      if (dt_exif_xmp_read(img, filename, 1))
      {
        res=1;
        break;
      }

      /* if current image in develop reload history */
      if (dt_dev_is_current_image(darktable.develop, imgid))
        dt_dev_reload_history_items (darktable.develop);

      dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED);
      dt_image_cache_read_release(darktable.image_cache, img);
      dt_mipmap_cache_remove(darktable.mipmap_cache, imgid);
    }
  }
  sqlite3_finalize(stmt);
  return res;
}
Esempio n. 4
0
static gboolean _lib_filmstrip_ratings_key_accel_callback(GtkAccelGroup *accel_group,
    GObject *aceeleratable, guint keyval,
    GdkModifierType modifier, gpointer data)
{
  int num = GPOINTER_TO_INT(data);
  switch (num)
  {
    case DT_VIEW_DESERT:
    case DT_VIEW_REJECT:
    case DT_VIEW_STAR_1:
    case DT_VIEW_STAR_2:
    case DT_VIEW_STAR_3:
    case DT_VIEW_STAR_4:
    case DT_VIEW_STAR_5:
    case 666:
    {
      int32_t mouse_over_id;
      DT_CTL_GET_GLOBAL(mouse_over_id, lib_image_mouse_over_id);
      if (mouse_over_id <= 0) return FALSE;
      /* get image from cache */

      int32_t activated_image = -1;

      activated_image = darktable.view_manager->proxy.filmstrip.activated_image(darktable.view_manager->proxy.filmstrip.module);

      int offset = 0;
      if(mouse_over_id == activated_image)
        offset = dt_collection_image_offset(mouse_over_id);

      const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, mouse_over_id);
      dt_image_t *image = dt_image_cache_write_get(darktable.image_cache, cimg);
      if (num == 666)
        image->flags &= ~0xf;
      else if (num == DT_VIEW_STAR_1 && ((image->flags & 0x7) == 1))
        image->flags &= ~0x7;
      else if(num == DT_VIEW_REJECT && ((image->flags & 0x7) == 6)) image->flags &= ~0x7;
      else
      {
        image->flags &= ~0x7;
        image->flags |= num;
      }
      dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_SAFE);
      dt_image_cache_read_release(darktable.image_cache, image);

      dt_collection_hint_message(darktable.collection); // More than this, we need to redraw all

      if(mouse_over_id == activated_image)
        if(_lib_filmstrip_imgid_in_collection(darktable.collection, mouse_over_id) == 0)
          dt_view_filmstrip_scroll_relative(0, offset);

      /* redraw all */
      dt_control_queue_redraw();
      break;
    }
    default:
      break;
  }
  return TRUE;
}
Esempio n. 5
0
/** add an image to a group */
void dt_grouping_add_to_group(int group_id, int image_id)
{
  // remove from old group
  dt_grouping_remove_from_group(image_id);

  dt_image_t *img = dt_image_cache_get(darktable.image_cache, image_id, 'w');
  img->group_id = group_id;
  dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_SAFE);
}
Esempio n. 6
0
/** remove an image from a group */
int dt_grouping_remove_from_group(int image_id)
{
  sqlite3_stmt *stmt;
  int new_group_id = -1;

  const dt_image_t *img = dt_image_cache_get(darktable.image_cache, image_id, 'r');
  int img_group_id = img->group_id;
  dt_image_cache_read_release(darktable.image_cache, img);
  if(img_group_id == image_id)
  {
    // get a new group_id for all the others in the group. also write it to the dt_image_t struct.
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
                                "select id from images where group_id = ?1 and id != ?2", -1, &stmt, NULL);
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, img_group_id);
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, image_id);
    while(sqlite3_step(stmt) == SQLITE_ROW)
    {
      int other_id = sqlite3_column_int(stmt, 0);
      if(new_group_id == -1) new_group_id = other_id;
      dt_image_t *other_img = dt_image_cache_get(darktable.image_cache, other_id, 'w');
      other_img->group_id = new_group_id;
      dt_image_cache_write_release(darktable.image_cache, other_img, DT_IMAGE_CACHE_SAFE);
    }
    sqlite3_finalize(stmt);

    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
                                "update images set group_id = ?1 where group_id = ?2 and id != ?3", -1, &stmt,
                                NULL);
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, new_group_id);
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, img_group_id);
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, image_id);
    sqlite3_step(stmt);
    sqlite3_finalize(stmt);
  }
  else
  {
    // change the group_id for this image.
    dt_image_t *wimg = dt_image_cache_get(darktable.image_cache, image_id, 'w');
    new_group_id = wimg->group_id;
    wimg->group_id = image_id;
    dt_image_cache_write_release(darktable.image_cache, wimg, DT_IMAGE_CACHE_SAFE);
  }
  return new_group_id;
}
Esempio n. 7
0
void dt_image_add_time_offset(const int imgid, const long int offset)
{
  const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, imgid);
  if (!cimg)
    return;

  // get the datetime_taken and calculate the new time
  gint  year;
  gint  month;
  gint  day;
  gint  hour;
  gint  minute;
  gint  seconds;

  if (sscanf(cimg->exif_datetime_taken, "%d:%d:%d %d:%d:%d",
             (int*)&year, (int*)&month, (int*)&day,
             (int*)&hour,(int*)&minute,(int*)&seconds) != 6)
  {
    fprintf(stderr,"broken exif time in db, '%s', imgid %d\n", cimg->exif_datetime_taken, imgid);
    dt_image_cache_read_release(darktable.image_cache, cimg);
    return;
  }

  GTimeZone *tz = g_time_zone_new_utc();
  GDateTime *datetime_original = g_date_time_new(tz, year, month, day, hour, minute, seconds);
  g_time_zone_unref(tz);
  if(!datetime_original)
  {
    dt_image_cache_read_release(darktable.image_cache, cimg);
    return;
  }

  // let's add our offset
  GDateTime *datetime_new = g_date_time_add_seconds(datetime_original, offset);
  g_date_time_unref(datetime_original);

  if(!datetime_new)
  {
    dt_image_cache_read_release(darktable.image_cache, cimg);
    return;
  }

  gchar *datetime = g_date_time_format(datetime_new, "%Y:%m:%d %H:%M:%S");
  g_date_time_unref(datetime_new);

  // update exif_datetime_taken in img
  if(datetime)
  {
    dt_image_t *img = dt_image_cache_write_get(darktable.image_cache, cimg);
    g_strlcpy(img->exif_datetime_taken, datetime, 20);
    dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_SAFE);
  }

  dt_image_cache_read_release(darktable.image_cache, cimg);
  g_free(datetime);
}
Esempio n. 8
0
static void remove_preset_flag(const int imgid)
{
  dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'w');

  // clear flag
  image->flags &= ~DT_IMAGE_AUTO_PRESETS_APPLIED;

  // write through to sql+xmp
  dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_SAFE);
}
Esempio n. 9
0
void dt_ratings_apply_to_image(int imgid, int rating)
{
  dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'w');
  // one star is a toggle, so you can easily reject images by removing the last star:
  if(((image->flags & 0x7) == 1) && (rating == 1)) rating = 0;
  image->flags = (image->flags & ~0x7) | (0x7 & rating);
  // synch through:
  dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_SAFE);

  dt_collection_hint_message(darktable.collection);
}
Esempio n. 10
0
/** make an image the representative of the group it is in */
int dt_grouping_change_representative(int image_id)
{
  sqlite3_stmt *stmt;

  dt_image_t *img = dt_image_cache_get(darktable.image_cache, image_id, 'w');
  int group_id = img->group_id;
  dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_SAFE);

  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select id from images where group_id = ?1", -1,
                              &stmt, NULL);
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, group_id);
  while(sqlite3_step(stmt) == SQLITE_ROW)
  {
    int other_id = sqlite3_column_int(stmt, 0);
    dt_image_t *other_img = dt_image_cache_get(darktable.image_cache, other_id, 'w');
    other_img->group_id = image_id;
    dt_image_cache_write_release(darktable.image_cache, other_img, DT_IMAGE_CACHE_SAFE);
  }
  sqlite3_finalize(stmt);

  return image_id;
}
Esempio n. 11
0
static gboolean _lib_filmstrip_button_press_callback(GtkWidget *w, GdkEventButton *e, gpointer user_data)
{
  dt_lib_module_t *self = (dt_lib_module_t *)user_data;
  dt_lib_filmstrip_t *strip = (dt_lib_filmstrip_t *)self->data;

  int32_t mouse_over_id = strip->mouse_over_id;

  /* is this an activation of image */
  if (e->button == 1 && e->type == GDK_2BUTTON_PRESS)
    if (mouse_over_id > 0)
    {
      strip->activated_image = mouse_over_id;
      dt_control_signal_raise(darktable.signals, DT_SIGNAL_VIEWMANAGER_FILMSTRIP_ACTIVATE);
      return TRUE;
    }


  /* let check if any thumb controls was clicked */
  switch(strip->image_over)
  {
    case DT_VIEW_DESERT:
      break;
    case DT_VIEW_REJECT:
    case DT_VIEW_STAR_1:
    case DT_VIEW_STAR_2:
    case DT_VIEW_STAR_3:
    case DT_VIEW_STAR_4:
    case DT_VIEW_STAR_5:
    {
      const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, mouse_over_id);
      dt_image_t *image = dt_image_cache_write_get(darktable.image_cache, cimg);
      image->dirty = 1;
      if(strip->image_over == DT_VIEW_STAR_1 && ((image->flags & 0x7) == 1)) image->flags &= ~0x7;
      else if(strip->image_over == DT_VIEW_REJECT && ((image->flags & 0x7) == 6)) image->flags &= ~0x7;
      else
      {
        image->flags &= ~0x7;
        image->flags |= strip->image_over;
      }
      dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_SAFE);
      dt_image_cache_read_release(darktable.image_cache, image);
      break;
    }

    default:
      return FALSE;
  }

  return TRUE;
}
Esempio n. 12
0
void dt_image_set_location(const int32_t imgid, double lon, double lat)
{
  /* fetch image from cache */
  const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, imgid);
  if (!cimg)
    return;
  dt_image_t *image = dt_image_cache_write_get(darktable.image_cache, cimg);

  /* set image location */
  image->longitude = lon;
  image->latitude = lat;

  /* store */
  dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_SAFE);
  dt_image_cache_read_release(darktable.image_cache, image);
}
Esempio n. 13
0
int dt_history_load_and_apply(int imgid, gchar *filename, int history_only)
{
  int res = 0;
  dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'w');
  if(img)
  {
    if(dt_exif_xmp_read(img, filename, history_only)) return 1;

    /* if current image in develop reload history */
    if(dt_dev_is_current_image(darktable.develop, imgid)) dt_dev_reload_history_items(darktable.develop);

    dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_SAFE);
    dt_mipmap_cache_remove(darktable.mipmap_cache, imgid);
  }
  return res;
}
Esempio n. 14
0
static gboolean _lib_filmstrip_ratings_key_accel_callback(GtkAccelGroup *accel_group,
                                                      GObject *aceeleratable, guint keyval,
                                                      GdkModifierType modifier, gpointer data)
{
  long int num = (long int)data;
  switch (num)
  {
    case DT_VIEW_DESERT:
    case DT_VIEW_REJECT:
    case DT_VIEW_STAR_1:
    case DT_VIEW_STAR_2:
    case DT_VIEW_STAR_3:
    case DT_VIEW_STAR_4:
    case DT_VIEW_STAR_5:
    case 666:
    {
      int32_t mouse_over_id;
      DT_CTL_GET_GLOBAL(mouse_over_id, lib_image_mouse_over_id);
      if (mouse_over_id <= 0) return FALSE;
      /* get image from cache */
      const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, mouse_over_id);
      dt_image_t *image = dt_image_cache_write_get(darktable.image_cache, cimg);
      if (num == 666) 
        image->flags &= ~0xf;
      else if (num == DT_VIEW_STAR_1 && ((image->flags & 0x7) == 1)) 
        image->flags &= ~0x7;
      else
      {
        image->flags &= ~0x7;
        image->flags |= num;
      }
      dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_SAFE);
      dt_image_cache_read_release(darktable.image_cache, image);

      /* redraw all */
      dt_control_queue_redraw();
      break;
    }
    default:
      break;
    }
    return TRUE;
}
Esempio n. 15
0
void dt_ratings_apply_to_selection (int rating)
{
  uint32_t count = dt_collection_get_selected_count(darktable.collection);
  if (count)
  {
    dt_control_log(ngettext("applying rating %d to %d image", "applying rating %d to %d images", count), rating, count);
#if 0 // not updating cache
    gchar query[1024]={0};
    g_snprintf(query,1024,
	       "update images set flags=(images.flags & ~7) | (7 & %d) where id in (select imgid from selected_images)",
	       rating
	       );
    DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), query, NULL, NULL, NULL);
#endif

    /* for each selected image update rating */
    sqlite3_stmt *stmt;
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select imgid from selected_images", -1, &stmt, NULL);
    while(sqlite3_step(stmt) == SQLITE_ROW)
    {
      const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, sqlite3_column_int(stmt, 0));
      dt_image_t *image = dt_image_cache_write_get(darktable.image_cache, cimg);
      image->flags = (image->flags & ~0x7) | (0x7 & rating);
      // synch through:
      dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_SAFE);
      dt_image_cache_read_release(darktable.image_cache, image);
    }
    sqlite3_finalize(stmt);

    /* redraw view */
    dt_control_queue_redraw_center();
  }
  else
    dt_control_log(_("no images selected to apply rating"));

}
Esempio n. 16
0
int main(int argc, char *arg[])
{
  bindtextdomain(GETTEXT_PACKAGE, DARKTABLE_LOCALEDIR);
  bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
  textdomain(GETTEXT_PACKAGE);

  if(!gtk_parse_args(&argc, &arg)) exit(1);

  // parse command line arguments
  char *input_filename = NULL;
  char *xmp_filename = NULL;
  char *output_filename = NULL;
  int file_counter = 0;
  int width = 0, height = 0, bpp = 0;
  gboolean verbose = FALSE, high_quality = TRUE, upscale = FALSE;

  int k;
  for(k = 1; k < argc; k++)
  {
    if(arg[k][0] == '-')
    {
      if(!strcmp(arg[k], "--help"))
      {
        usage(arg[0]);
        exit(1);
      }
      else if(!strcmp(arg[k], "--version"))
      {
        printf("this is darktable-cli %s\ncopyright (c) 2012-2016 johannes hanika, tobias ellinghaus\n",
               darktable_package_version);
        exit(1);
      }
      else if(!strcmp(arg[k], "--width") && argc > k + 1)
      {
        k++;
        width = MAX(atoi(arg[k]), 0);
      }
      else if(!strcmp(arg[k], "--height") && argc > k + 1)
      {
        k++;
        height = MAX(atoi(arg[k]), 0);
      }
      else if(!strcmp(arg[k], "--bpp") && argc > k + 1)
      {
        k++;
        bpp = MAX(atoi(arg[k]), 0);
        fprintf(stderr, "%s %d\n",
                _("TODO: sorry, due to API restrictions we currently cannot set the BPP to"), bpp);
      }
      else if(!strcmp(arg[k], "--hq") && argc > k + 1)
      {
        k++;
        gchar *str = g_ascii_strup(arg[k], -1);
        if(!g_strcmp0(str, "0") || !g_strcmp0(str, "FALSE"))
          high_quality = FALSE;
        else if(!g_strcmp0(str, "1") || !g_strcmp0(str, "TRUE"))
          high_quality = TRUE;
        else
        {
          fprintf(stderr, "%s: %s\n", _("unknown option for --hq"), arg[k]);
          usage(arg[0]);
          exit(1);
        }
        g_free(str);
      }
      else if(!strcmp(arg[k], "--upscale") && argc > k + 1)
      {
        k++;
        gchar *str = g_ascii_strup(arg[k], -1);
        if(!g_strcmp0(str, "0") || !g_strcmp0(str, "FALSE"))
          upscale = FALSE;
        else if(!g_strcmp0(str, "1") || !g_strcmp0(str, "TRUE"))
          upscale= TRUE;
        else
        {
          fprintf(stderr, "%s: %s\n", _("unknown option for --upscale"), arg[k]);
          usage(arg[0]);
          exit(1);
        }
        g_free(str);
      }
      else if(!strcmp(arg[k], "-v") || !strcmp(arg[k], "--verbose"))
      {
        verbose = TRUE;
      }
      else if(!strcmp(arg[k], "--core"))
      {
        // everything from here on should be passed to the core
        k++;
        break;
      }
    }
    else
    {
      if(file_counter == 0)
        input_filename = arg[k];
      else if(file_counter == 1)
        xmp_filename = arg[k];
      else if(file_counter == 2)
        output_filename = arg[k];
      file_counter++;
    }
  }

  int m_argc = 0;
  char **m_arg = malloc((5 + argc - k + 1) * sizeof(char *));
  m_arg[m_argc++] = "darktable-cli";
  m_arg[m_argc++] = "--library";
  m_arg[m_argc++] = ":memory:";
  m_arg[m_argc++] = "--conf";
  m_arg[m_argc++] = "write_sidecar_files=FALSE";
  for(; k < argc; k++) m_arg[m_argc++] = arg[k];
  m_arg[m_argc] = NULL;

  if(file_counter < 2 || file_counter > 3)
  {
    usage(arg[0]);
    free(m_arg);
    exit(1);
  }
  else if(file_counter == 2)
  {
    // no xmp file given
    output_filename = xmp_filename;
    xmp_filename = NULL;
  }

  if(g_file_test(output_filename, G_FILE_TEST_IS_DIR))
  {
    fprintf(stderr, _("error: output file is a directory. please specify file name"));
    fprintf(stderr, "\n");
    free(m_arg);
    exit(1);
  }

  // the output file already exists, so there will be a sequence number added
  if(g_file_test(output_filename, G_FILE_TEST_EXISTS))
  {
    fprintf(stderr, "%s\n", _("output file already exists, it will get renamed"));
  }

  // init dt without gui:
  if(dt_init(m_argc, m_arg, 0, NULL))
  {
    free(m_arg);
    exit(1);
  }

  GList *id_list = NULL;

  if(g_file_test(input_filename, G_FILE_TEST_IS_DIR))
  {
    int filmid = dt_film_import(input_filename);
    if(!filmid)
    {
      fprintf(stderr, _("error: can't open folder %s"), input_filename);
      fprintf(stderr, "\n");
      free(m_arg);
      exit(1);
    }
    id_list = dt_film_get_image_ids(filmid);
  }
  else
  {
    dt_film_t film;
    int id = 0;
    int filmid = 0;

    gchar *directory = g_path_get_dirname(input_filename);
    filmid = dt_film_new(&film, directory);
    id = dt_image_import(filmid, input_filename, TRUE);
    if(!id)
    {
      fprintf(stderr, _("error: can't open file %s"), input_filename);
      fprintf(stderr, "\n");
      free(m_arg);
      exit(1);
    }
    g_free(directory);

    id_list = g_list_append(id_list, GINT_TO_POINTER(id));
  }

  int total = g_list_length(id_list);

  if(total == 0)
  {
    fprintf(stderr, _("no images to export, aborting\n"));
    free(m_arg);
    exit(1);
  }

  // attach xmp, if requested:
  if(xmp_filename)
  {
    for(GList *iter = id_list; iter; iter = g_list_next(iter))
    {
      int id = GPOINTER_TO_INT(iter->data);
      dt_image_t *image = dt_image_cache_get(darktable.image_cache, id, 'w');
      dt_exif_xmp_read(image, xmp_filename, 1);
      // don't write new xmp:
      dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_RELAXED);
    }
  }

  // print the history stack. only look at the first image and assume all got the same processing applied
  if(verbose)
  {
    int id = GPOINTER_TO_INT(id_list->data);
    gchar *history = dt_history_get_items_as_string(id);
    if(history)
      printf("%s\n", history);
    else
      printf("[%s]\n", _("empty history stack"));
  }

  // try to find out the export format from the output_filename
  char *ext = output_filename + strlen(output_filename);
  while(ext > output_filename && *ext != '.') ext--;
  *ext = '\0';
  ext++;

  if(!strcmp(ext, "jpg")) ext = "jpeg";

  if(!strcmp(ext, "tif")) ext = "tiff";

  // init the export data structures
  dt_imageio_module_format_t *format;
  dt_imageio_module_storage_t *storage;
  dt_imageio_module_data_t *sdata, *fdata;

  storage = dt_imageio_get_storage_by_name("disk"); // only exporting to disk makes sense
  if(storage == NULL)
  {
    fprintf(
        stderr, "%s\n",
        _("cannot find disk storage module. please check your installation, something seems to be broken."));
    free(m_arg);
    exit(1);
  }

  sdata = storage->get_params(storage);
  if(sdata == NULL)
  {
    fprintf(stderr, "%s\n", _("failed to get parameters from storage module, aborting export ..."));
    free(m_arg);
    exit(1);
  }

  // and now for the really ugly hacks. don't tell your children about this one or they won't sleep at night
  // any longer ...
  g_strlcpy((char *)sdata, output_filename, DT_MAX_PATH_FOR_PARAMS);
  // all is good now, the last line didn't happen.

  format = dt_imageio_get_format_by_name(ext);
  if(format == NULL)
  {
    fprintf(stderr, _("unknown extension '.%s'"), ext);
    fprintf(stderr, "\n");
    free(m_arg);
    exit(1);
  }

  fdata = format->get_params(format);
  if(fdata == NULL)
  {
    fprintf(stderr, "%s\n", _("failed to get parameters from format module, aborting export ..."));
    free(m_arg);
    exit(1);
  }

  uint32_t w, h, fw, fh, sw, sh;
  fw = fh = sw = sh = 0;
  storage->dimension(storage, sdata, &sw, &sh);
  format->dimension(format, fdata, &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;

  fdata->max_width = width;
  fdata->max_height = 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;
  fdata->style[0] = '\0';
  fdata->style_append = 0;

  if(storage->initialize_store)
  {
    storage->initialize_store(storage, sdata, &format, &fdata, &id_list, high_quality, upscale);

    format->set_params(format, fdata, format->params_size(format));
    storage->set_params(storage, sdata, storage->params_size(storage));
  }

  // TODO: add a callback to set the bpp without going through the config

  int num = 1;
  for(GList *iter = id_list; iter; iter = g_list_next(iter), num++)
  {
    int id = GPOINTER_TO_INT(iter->data);
    storage->store(storage, sdata, id, format, fdata, num, total, high_quality, upscale);
  }

  // cleanup time
  if(storage->finalize_store) storage->finalize_store(storage, sdata);
  storage->free_params(storage, sdata);
  format->free_params(format, fdata);
  g_list_free(id_list);

  dt_cleanup();

  free(m_arg);
}
Esempio n. 17
0
static void releasewriteimage(lua_State*L,dt_image_t* image)
{
  dt_image_cache_write_release(darktable.image_cache,image,DT_IMAGE_CACHE_SAFE);
  releasereadimage(L,image);
}
Esempio n. 18
0
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;
}
Esempio n. 19
0
int32_t dt_image_move(const int32_t imgid, const int32_t filmid)
{
  //TODO: several places where string truncation could occur unnoticed
  int32_t result = -1;
  gchar oldimg[DT_MAX_PATH_LEN] = {0};
  gchar newimg[DT_MAX_PATH_LEN] = {0};
  dt_image_full_path(imgid, oldimg, DT_MAX_PATH_LEN);
  gchar *newdir = NULL;

  sqlite3_stmt *film_stmt;
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
                              "select folder from film_rolls where id = ?1", -1, &film_stmt, NULL);
  DT_DEBUG_SQLITE3_BIND_INT(film_stmt, 1, filmid);
  if(sqlite3_step(film_stmt) == SQLITE_ROW)
    newdir = g_strdup((gchar *) sqlite3_column_text(film_stmt, 0));
  sqlite3_finalize(film_stmt);

  if(newdir)
  {
    gchar *imgbname = g_path_get_basename(oldimg);
    g_snprintf(newimg, DT_MAX_PATH_LEN, "%s%c%s", newdir, G_DIR_SEPARATOR, imgbname);
    g_free(imgbname);
    g_free(newdir);

    // statement for getting ids of the image to be moved and it's duplicates
    sqlite3_stmt *duplicates_stmt;
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
                                "select id from images where filename in (select filename from images "
                                "where id = ?1) and film_id in (select film_id from images where id = ?1)",
                                -1, &duplicates_stmt, NULL);

    // move image
    // TODO: Use gio's' g_file_move instead of g_rename?
    if (!g_file_test(newimg, G_FILE_TEST_EXISTS)
        && (g_rename(oldimg, newimg) == 0))
    {
      // first move xmp files of image and duplicates
      GList *dup_list = NULL;
      DT_DEBUG_SQLITE3_BIND_INT(duplicates_stmt, 1, imgid);
      while (sqlite3_step(duplicates_stmt) == SQLITE_ROW)
      {
        int32_t id = sqlite3_column_int(duplicates_stmt, 0);
        dup_list = g_list_append(dup_list, GINT_TO_POINTER(id));
        gchar oldxmp[512], newxmp[512];
        g_strlcpy(oldxmp, oldimg, 512);
        g_strlcpy(newxmp, newimg, 512);
        dt_image_path_append_version(id, oldxmp, 512);
        dt_image_path_append_version(id, newxmp, 512);
        g_strlcat(oldxmp, ".xmp", 512);
        g_strlcat(newxmp, ".xmp", 512);
        if (g_file_test(oldxmp, G_FILE_TEST_EXISTS))
          (void)g_rename(oldxmp, newxmp);
      }
      sqlite3_reset(duplicates_stmt);
      sqlite3_clear_bindings(duplicates_stmt);

      // then update database and cache
      // if update was performed in above loop, dt_image_path_append_version()
      // would return wrong version!
      while (dup_list)
      {
        long int id = GPOINTER_TO_INT(dup_list->data);
        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->film_id = filmid;
        // 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);
        dup_list = g_list_delete_link(dup_list, dup_list);
      }
      g_list_free(dup_list);
      result = 0;
    }
  }

  return result;
}
Esempio n. 20
0
int button_pressed(dt_view_t *self, double x, double y, int which, int type, uint32_t state)
{
  dt_library_t *lib = (dt_library_t *)self->data;
  lib->modifiers = state;
  lib->button = which;
  lib->select_offset_x = lib->zoom_x;
  lib->select_offset_y = lib->zoom_y;
  lib->select_offset_x += x;
  lib->select_offset_y += y;
  lib->pan = 1;
  if(which == 1) dt_control_change_cursor(GDK_HAND1);
  if(which == 1 && type == GDK_2BUTTON_PRESS) return 0;
  // image button pressed?
  if(which == 1)
  {
    switch(lib->image_over)
    {
      case DT_VIEW_DESERT:
        break;
      case DT_VIEW_REJECT:
      case DT_VIEW_STAR_1:
      case DT_VIEW_STAR_2:
      case DT_VIEW_STAR_3:
      case DT_VIEW_STAR_4:
      case DT_VIEW_STAR_5:
      {
        int32_t mouse_over_id;
        DT_CTL_GET_GLOBAL(mouse_over_id, lib_image_mouse_over_id);
        const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, mouse_over_id);
        dt_image_t *image = dt_image_cache_write_get(darktable.image_cache, cimg);
        if(image)
        {
          if(lib->image_over == DT_VIEW_STAR_1 && ((image->flags & 0x7) == 1)) image->flags &= ~0x7;
          else if(lib->image_over == DT_VIEW_REJECT && ((image->flags & 0x7) == 6)) image->flags &= ~0x7;
          else
          {
            image->flags &= ~0x7;
            image->flags |= lib->image_over;
          }
          dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_SAFE);
        }
        dt_image_cache_read_release(darktable.image_cache, image);
        break;
      }
      case DT_VIEW_GROUP:
      {
        int32_t mouse_over_id;
        DT_CTL_GET_GLOBAL(mouse_over_id, lib_image_mouse_over_id);
        const dt_image_t *image = dt_image_cache_read_get(darktable.image_cache, mouse_over_id);
        if(!image) return 0;
        int group_id = image->group_id;
        int id = image->id;
        dt_image_cache_read_release(darktable.image_cache, image);
        if(state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) // just add the whole group to the selection. TODO: make this also work for collapsed groups.
        {
          sqlite3_stmt *stmt;
          DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert or ignore into selected_images select id from images where group_id = ?1", -1, &stmt, NULL);
          DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, group_id);
          sqlite3_step(stmt);
          sqlite3_finalize(stmt);
        }
        else if(group_id == darktable.gui->expanded_group_id) // the group is already expanded, so ...
        {
          if(id == darktable.gui->expanded_group_id) // ... collapse it
            darktable.gui->expanded_group_id = -1;
          else                                       // ... make the image the new representative of the group
            darktable.gui->expanded_group_id = dt_grouping_change_representative(id);
        }
        else // expand the group
          darktable.gui->expanded_group_id = group_id;
        dt_collection_update_query(darktable.collection);
        break;
      }
      default:
        return 0;
    }
  }
  return 1;
}
Esempio n. 21
0
int main(int argc, char *arg[])
{
  bindtextdomain (GETTEXT_PACKAGE, DARKTABLE_LOCALEDIR);
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
  textdomain (GETTEXT_PACKAGE);

  gtk_init (&argc, &arg);

  // parse command line arguments

  char *image_filename = NULL;
  char *xmp_filename = NULL;
  char *output_filename = NULL;
  int file_counter = 0;
  int width = 0, height = 0, bpp = 0;
  gboolean verbose = FALSE, high_quality = TRUE;

  for(int k=1; k<argc; k++)
  {
    if(arg[k][0] == '-')
    {
      if(!strcmp(arg[k], "--help"))
      {
        usage(arg[0]);
        exit(1);
      }
      else if(!strcmp(arg[k], "--version"))
      {
        printf("this is darktable-cli\ncopyright (c) 2012-2013 johannes hanika, tobias ellinghaus\n");
        exit(1);
      }
      else if(!strcmp(arg[k], "--width"))
      {
        k++;
        width = MAX(atoi(arg[k]), 0);
      }
      else if(!strcmp(arg[k], "--height"))
      {
        k++;
        height = MAX(atoi(arg[k]), 0);
      }
      else if(!strcmp(arg[k], "--bpp"))
      {
        k++;
        bpp = MAX(atoi(arg[k]), 0);
        fprintf(stderr, "%s %d\n", _("TODO: sorry, due to api restrictions we currently cannot set the bpp to"), bpp);
      }
      else if(!strcmp(arg[k], "--hq"))
      {
        k++;
        gchar *str = g_ascii_strup(arg[k], -1);
        if(!g_strcmp0(str, "0") || !g_strcmp0(str, "FALSE"))
          high_quality = FALSE;
        else if(!g_strcmp0(str, "1") || !g_strcmp0(str, "TRUE"))
          high_quality = TRUE;
        else
        {
          fprintf(stderr, "%s: %s\n", _("Unknown option for --hq"), arg[k]);
          usage(arg[0]);
          exit(1);
        }
        g_free(str);
      }
      else if(!strcmp(arg[k], "-v") || !strcmp(arg[k], "--verbose"))
      {
        verbose = TRUE;
      }

    }
    else
    {
      if(file_counter == 0)
        image_filename = arg[k];
      else if(file_counter == 1)
        xmp_filename = arg[k];
      else if(file_counter == 2)
        output_filename = arg[k];
      file_counter++;
    }
  }

  if(file_counter < 2 || file_counter > 3)
  {
    usage(arg[0]);
    exit(1);
  }
  else if(file_counter == 2)
  {
    // no xmp file given
    output_filename = xmp_filename;
    xmp_filename = NULL;
  }

  // the output file already exists, so there will be a sequence number added
  if(g_file_test(output_filename, G_FILE_TEST_EXISTS))
  {
    fprintf(stderr, "%s\n", _("output file already exists, it will get renamed"));
  }

  char *m_arg[] = {"darktable-cli", "--library", ":memory:", NULL};
  // init dt without gui:
  if(dt_init(3, m_arg, 0)) exit(1);

  dt_film_t film;
  int id = 0;
  int filmid = 0;

  gchar *directory = g_path_get_dirname(image_filename);
  filmid = dt_film_new(&film, directory);
  id = dt_image_import(filmid, image_filename, TRUE);
  if(!id)
  {
    fprintf(stderr, _("error: can't open file %s"), image_filename);
    fprintf(stderr, "\n");
    exit(1);
  }
  g_free(directory);

  // attach xmp, if requested:
  if(xmp_filename)
  {
    const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, id);
    dt_image_t *image = dt_image_cache_write_get(darktable.image_cache, cimg);
    dt_exif_xmp_read(image, xmp_filename, 1);
    // don't write new xmp:
    dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_RELAXED);
    dt_image_cache_read_release(darktable.image_cache, image);
  }

  // print the history stack
  if(verbose)
  {
    gchar *history = dt_history_get_items_as_string(id);
    if(history)
      printf("%s\n", history);
    else
      printf("[%s]\n", _("empty history stack"));
  }

  // try to find out the export format from the output_filename
  char *ext = output_filename + strlen(output_filename);
  while(ext > output_filename && *ext != '.') ext--;
  *ext = '\0';
  ext++;

  if(!strcmp(ext, "jpg"))
    ext = "jpeg";

  // init the export data structures
  int size = 0, dat_size = 0;
  dt_imageio_module_format_t *format;
  dt_imageio_module_storage_t *storage;
  dt_imageio_module_data_t *sdata, *fdata;

  storage = dt_imageio_get_storage_by_name("disk"); // only exporting to disk makes sense
  if(storage == NULL)
  {
    fprintf(stderr, "%s\n", _("cannot find disk storage module. please check your installation, something seems to be broken."));
    exit(1);
  }

  sdata = storage->get_params(storage, &size);
  if(sdata == NULL)
  {
    fprintf(stderr, "%s\n", _("failed to get parameters from storage module, aborting export ..."));
    exit(1);
  }

  // and now for the really ugly hacks. don't tell your children about this one or they won't sleep at night any longer ...
  g_strlcpy((char*)sdata, output_filename, DT_MAX_PATH_LEN);
  // all is good now, the last line didn't happen.

  format = dt_imageio_get_format_by_name(ext);
  if(format == NULL)
  {
    fprintf(stderr, _("unknown extension '.%s'"), ext);
    fprintf(stderr, "\n");
    exit(1);
  }

  fdata = format->get_params(format, &dat_size);
  if(fdata == NULL)
  {
    fprintf(stderr, "%s\n", _("failed to get parameters from format module, aborting export ..."));
    exit(1);
  }

  uint32_t w,h,fw,fh,sw,sh;
  fw=fh=sw=sh=0;
  storage->dimension(storage, &sw, &sh);
  format->dimension(format, &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;

  fdata->max_width  = width;
  fdata->max_height = 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;
  fdata->style[0] = '\0';

  //TODO: add a callback to set the bpp without going through the config

  storage->store(storage,sdata, id, format, fdata, 1, 1, high_quality);

  // cleanup time
  if(storage->finalize_store) storage->finalize_store(storage, sdata);
  storage->free_params(storage, sdata);
  format->free_params(format, fdata);

  dt_cleanup();
}
Esempio n. 22
0
void
dt_mipmap_cache_read_get(
  dt_mipmap_cache_t *cache,
  dt_mipmap_buffer_t *buf,
  const uint32_t imgid,
  const dt_mipmap_size_t mip,
  const dt_mipmap_get_flags_t flags)
{
  const uint32_t key = get_key(imgid, mip);
  if(flags == DT_MIPMAP_TESTLOCK)
  {
    // simple case: only get and lock if it's there.
    struct dt_mipmap_buffer_dsc* dsc = (struct dt_mipmap_buffer_dsc*)dt_cache_read_testget(&cache->mip[mip].cache, key);
    if(dsc)
    {
      buf->width  = dsc->width;
      buf->height = dsc->height;
      buf->imgid  = imgid;
      buf->size   = mip;
      // skip to next 8-byte alignment, for sse buffers.
      buf->buf    = (uint8_t *)(dsc+1);
    }
    else
    {
      // set to NULL if failed.
      buf->width = buf->height = 0;
      buf->imgid = 0;
      buf->size  = DT_MIPMAP_NONE;
      buf->buf   = NULL;
    }
  }
  else if(flags == DT_MIPMAP_PREFETCH)
  {
    // and opposite: prefetch without locking
    if(mip > DT_MIPMAP_FULL || mip < DT_MIPMAP_0) return;
    dt_job_t j;
    dt_image_load_job_init(&j, imgid, mip);
    // if the job already exists, make it high-priority, if not, add it:
    if(dt_control_revive_job(darktable.control, &j) < 0)
      dt_control_add_job(darktable.control, &j);
  }
  else if(flags == DT_MIPMAP_BLOCKING)
  {
    // simple case: blocking get
    struct dt_mipmap_buffer_dsc* dsc = (struct dt_mipmap_buffer_dsc*)dt_cache_read_get(&cache->mip[mip].cache, key);
    if(!dsc)
    {
      // should never happen for anything but full images which have been moved.
      assert(mip == DT_MIPMAP_FULL || mip == DT_MIPMAP_F);
      // fprintf(stderr, "[mipmap cache get] no data in cache for imgid %u size %d!\n", imgid, mip);
      // sorry guys, no image for you :(
      buf->width = buf->height = 0;
      buf->imgid = 0;
      buf->size  = DT_MIPMAP_NONE;
      buf->buf   = NULL;
    }
    else
    {
      // fprintf(stderr, "[mipmap cache get] found data in cache for imgid %u size %d\n", imgid, mip);
      // uninitialized?
      //assert(dsc->flags & DT_MIPMAP_BUFFER_DSC_FLAG_GENERATE || dsc->size == 0);
      if(dsc->flags & DT_MIPMAP_BUFFER_DSC_FLAG_GENERATE)
      {
        __sync_fetch_and_add (&(cache->mip[mip].stats_fetches), 1);
        // fprintf(stderr, "[mipmap cache get] now initializing buffer for img %u mip %d!\n", imgid, mip);
        // we're write locked here, as requested by the alloc callback.
        // now fill it with data:
        if(mip == DT_MIPMAP_FULL)
        {
          // load the image:
          // make sure we access the r/w lock as shortly as possible!
          dt_image_t buffered_image;
          const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, imgid);
          buffered_image = *cimg;
          // dt_image_t *img = dt_image_cache_write_get(darktable.image_cache, cimg);
          // dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED);
          dt_image_cache_read_release(darktable.image_cache, cimg);

          char filename[DT_MAX_PATH_LEN];
          gboolean from_cache = TRUE;
          dt_image_full_path(buffered_image.id, filename, DT_MAX_PATH_LEN, &from_cache);

          dt_mipmap_cache_allocator_t a = (dt_mipmap_cache_allocator_t)&dsc;
          struct dt_mipmap_buffer_dsc* prvdsc = dsc;
          dt_imageio_retval_t ret = dt_imageio_open(&buffered_image, filename, a);
          if(dsc != prvdsc)
          {
            // fprintf(stderr, "[mipmap cache] realloc %p\n", data);
            // write back to cache, too.
            // in case something went wrong, still keep the buffer and return it to the hashtable
            // so we don't produce mem leaks or unnecessary mem fragmentation.
            dt_cache_realloc(&cache->mip[mip].cache, key, 1, (void*)dsc);
          }
          if(ret != DT_IMAGEIO_OK)
          {
            // fprintf(stderr, "[mipmap read get] error loading image: %d\n", ret);
            //
            // we can only return a zero dimension buffer if the buffer has been allocated.
            // in case dsc couldn't be allocated and points to the static buffer, it contains
            // a dead image already.
            if((void *)dsc != (void *)dt_mipmap_cache_static_dead_image) dsc->width = dsc->height = 0;
          }
          else
          {
            // swap back new image data:
            cimg = dt_image_cache_read_get(darktable.image_cache, imgid);
            dt_image_t *img = dt_image_cache_write_get(darktable.image_cache, cimg);
            *img = buffered_image;
            // fprintf(stderr, "[mipmap read get] initializing full buffer img %u with %u %u -> %d %d (%p)\n", imgid, data[0], data[1], img->width, img->height, data);
            // don't write xmp for this (we only changed db stuff):
            dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED);
            dt_image_cache_read_release(darktable.image_cache, img);
          }
        }
        else if(mip == DT_MIPMAP_F)
        {
          _init_f((float *)(dsc+1), &dsc->width, &dsc->height, imgid);
        }
        else
        {
          // 8-bit thumbs, possibly need to be compressed:
          if(cache->compression_type)
          {
            // get per-thread temporary storage without malloc from a separate cache:
            const int key = dt_control_get_threadid();
            // const void *cbuf =
            dt_cache_read_get(&cache->scratchmem.cache, key);
            uint8_t *scratchmem = (uint8_t *)dt_cache_write_get(&cache->scratchmem.cache, key);
            _init_8(scratchmem, &dsc->width, &dsc->height, imgid, mip);
            buf->width  = dsc->width;
            buf->height = dsc->height;
            buf->imgid  = imgid;
            buf->size   = mip;
            buf->buf = (uint8_t *)(dsc+1);
            dt_mipmap_cache_compress(buf, scratchmem);
            dt_cache_write_release(&cache->scratchmem.cache, key);
            dt_cache_read_release(&cache->scratchmem.cache, key);
          }
          else
          {
            _init_8((uint8_t *)(dsc+1), &dsc->width, &dsc->height, imgid, mip);
          }
        }
        dsc->flags &= ~DT_MIPMAP_BUFFER_DSC_FLAG_GENERATE;
        // drop the write lock
        dt_cache_write_release(&cache->mip[mip].cache, key);
        /* raise signal that mipmaps has been flushed to cache */
        dt_control_signal_raise(darktable.signals, DT_SIGNAL_DEVELOP_MIPMAP_UPDATED);
      }
      buf->width  = dsc->width;
      buf->height = dsc->height;
      buf->imgid  = imgid;
      buf->size   = mip;
      buf->buf = (uint8_t *)(dsc+1);
      if(dsc->width == 0 || dsc->height == 0)
      {
        // fprintf(stderr, "[mipmap cache get] got a zero-sized image for img %u mip %d!\n", imgid, mip);
        if(mip < DT_MIPMAP_F)       dead_image_8(buf);
        else if(mip == DT_MIPMAP_F) dead_image_f(buf);
        else buf->buf = NULL; // full images with NULL buffer have to be handled, indicates `missing image'
      }
    }
  }
  else if(flags == DT_MIPMAP_BEST_EFFORT)
  {
    __sync_fetch_and_add (&(cache->mip[mip].stats_requests), 1);
    // best-effort, might also return NULL.
    // never decrease mip level for float buffer or full image:
    dt_mipmap_size_t min_mip = (mip >= DT_MIPMAP_F) ? mip : DT_MIPMAP_0;
    for(int k=mip; k>=min_mip && k>=0; k--)
    {
      // already loaded?
      dt_mipmap_cache_read_get(cache, buf, imgid, k, DT_MIPMAP_TESTLOCK);
      if(buf->buf && buf->width > 0 && buf->height > 0)
      {
        if(mip != k) __sync_fetch_and_add (&(cache->mip[k].stats_standin), 1);
        return;
      }
      // didn't succeed the first time? prefetch for later!
      if(mip == k)
      {
        __sync_fetch_and_add (&(cache->mip[mip].stats_near_match), 1);
        dt_mipmap_cache_read_get(cache, buf, imgid, mip, DT_MIPMAP_PREFETCH);
      }
    }
    __sync_fetch_and_add (&(cache->mip[mip].stats_misses), 1);
    // fprintf(stderr, "[mipmap cache get] image not found in cache: imgid %u mip %d!\n", imgid, mip);
    // nothing found :(
    buf->buf   = NULL;
    buf->imgid = 0;
    buf->size  = DT_MIPMAP_NONE;
    buf->width = buf->height = 0;
  }
}
Esempio n. 23
0
static gboolean _lib_filmstrip_button_press_callback(GtkWidget *w, GdkEventButton *e, gpointer user_data)
{
  dt_lib_module_t *self = (dt_lib_module_t *)user_data;
  dt_lib_filmstrip_t *strip = (dt_lib_filmstrip_t *)self->data;

  int32_t mouse_over_id = strip->mouse_over_id;
  strip->select = DT_LIB_FILMSTRIP_SELECT_NONE;

  if (e->button == 1)
  {
    if(e->type == GDK_BUTTON_PRESS)
    {
      /* let check if any thumb controls was clicked */
      switch(strip->image_over)
      {
        case DT_VIEW_DESERT:
          /* is this an activation of image */
          if ((e->state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK)) == 0)
            strip->select = DT_LIB_FILMSTRIP_SELECT_SINGLE;
          else if ((e->state & (GDK_CONTROL_MASK)) == GDK_CONTROL_MASK)
            strip->select = DT_LIB_FILMSTRIP_SELECT_TOGGLE;
          else if ((e->state & (GDK_SHIFT_MASK)) == GDK_SHIFT_MASK)
            strip->select = DT_LIB_FILMSTRIP_SELECT_RANGE;
          if(strip->select != DT_LIB_FILMSTRIP_SELECT_NONE)
          {
            strip->select_id = mouse_over_id;
            return TRUE;
          }
          break;
        case DT_VIEW_REJECT:
        case DT_VIEW_STAR_1:
        case DT_VIEW_STAR_2:
        case DT_VIEW_STAR_3:
        case DT_VIEW_STAR_4:
        case DT_VIEW_STAR_5:
        {
          int offset = 0;
          if(mouse_over_id == strip->activated_image)
            offset = dt_collection_image_offset(mouse_over_id);

          const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, mouse_over_id);
          dt_image_t *image = dt_image_cache_write_get(darktable.image_cache, cimg);
          if(strip->image_over == DT_VIEW_STAR_1 && ((image->flags & 0x7) == 1)) image->flags &= ~0x7;
          else if(strip->image_over == DT_VIEW_REJECT && ((image->flags & 0x7) == 6)) image->flags &= ~0x7;
          else
          {
            image->flags &= ~0x7;
            image->flags |= strip->image_over;
          }
          dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_SAFE);
          dt_image_cache_read_release(darktable.image_cache, image);


          dt_collection_hint_message(darktable.collection); // More than this, we need to redraw all

          if(mouse_over_id == strip->activated_image)
            if(_lib_filmstrip_imgid_in_collection(darktable.collection, mouse_over_id) == 0)
              dt_view_filmstrip_scroll_relative(0, offset);

          gtk_widget_queue_draw(darktable.view_manager->proxy.filmstrip.module->widget);
          return TRUE;
        }

        default:
          return FALSE;
      }
    }
    else if(e->type == GDK_2BUTTON_PRESS)
    {
      if (mouse_over_id > 0)
      {
        strip->activated_image = mouse_over_id;
        dt_control_signal_raise(darktable.signals, DT_SIGNAL_VIEWMANAGER_FILMSTRIP_ACTIVATE);
        return TRUE;
      }
    }
  }

  return FALSE;
}
Esempio n. 24
0
static void
auto_apply_presets(dt_develop_t *dev)
{
  const int imgid = dev->image_storage.id;

  if(imgid <= 0) return;
  int run = 0;
  const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, imgid);
  if(!(cimg->flags & DT_IMAGE_AUTO_PRESETS_APPLIED))
    run = 1;

  // flag was already set? only apply presets once in the lifetime of a history stack.
  // (the flag will be cleared when removing it)
  if(!run || cimg->id <= 0)
  {
    dt_image_cache_read_release(darktable.image_cache, cimg);
    return;
  }

  // keep locked, we want to be alone messing with the history of the poor fellow:
  dt_image_t *image = dt_image_cache_write_get(darktable.image_cache, cimg);
  // be extra sure that we don't mess up history in separate threads:
  dt_pthread_mutex_lock(&darktable.db_insert);

  // cleanup
  DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db),
                        "delete from memory.history",
                        NULL, NULL, NULL);
  const char *preset_table[2] = {"presets", "legacy_presets"};
  const int legacy = (image->flags & DT_IMAGE_NO_LEGACY_PRESETS) ? 0 : 1;
  char query[1024];
  snprintf(query, 1024,
           "insert into memory.history select ?1, 0, op_version, operation, op_params, enabled, blendop_params, blendop_version, multi_priority, multi_name "
           "from %s where autoapply=1 and "
           "?2 like model and ?3 like maker and ?4 like lens and "
           "?5 between iso_min and iso_max and "
           "?6 between exposure_min and exposure_max and "
           "?7 between aperture_min and aperture_max and "
           "?8 between focal_length_min and focal_length_max and "
           "(isldr = 0 or isldr=?9) order by writeprotect desc, "
           "length(model), length(maker), length(lens)", preset_table[legacy]);
  // query for all modules at once:
  sqlite3_stmt *stmt;
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), query, -1, &stmt, NULL);
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
  DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, cimg->exif_model, strlen(cimg->exif_model), SQLITE_TRANSIENT);
  DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 3, cimg->exif_maker, strlen(cimg->exif_maker), SQLITE_TRANSIENT);
  DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 4, cimg->exif_lens,  strlen(cimg->exif_lens),  SQLITE_TRANSIENT);
  DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 5, fmaxf(0.0f, fminf(1000000, cimg->exif_iso)));
  DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 6, fmaxf(0.0f, fminf(1000000, cimg->exif_exposure)));
  DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 7, fmaxf(0.0f, fminf(1000000, cimg->exif_aperture)));
  DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 8, fmaxf(0.0f, fminf(1000000, cimg->exif_focal_length)));
  // 0: dontcare, 1: ldr, 2: raw
  DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 9, 2-dt_image_is_ldr(cimg));

  if(sqlite3_step(stmt) == SQLITE_DONE)
  {
    sqlite3_finalize(stmt);
    int cnt = 0;
    // count what we found:
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
                                "select count(*) from memory.history",
                                -1, &stmt, NULL);
    if(sqlite3_step(stmt) == SQLITE_ROW)
    {
      // if there is anything..
      cnt = sqlite3_column_int(stmt, 0);
      sqlite3_finalize(stmt);
      // fprintf(stderr, "[auto_apply_presets] imageid %d found %d matching presets (legacy %d)\n", imgid, cnt, legacy);
      // advance the current history by that amount:
      DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
                                  "update history set num=num+?1 where imgid=?2",
                                  -1, &stmt, NULL);
      DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, cnt);
      DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);

      if(sqlite3_step(stmt) == SQLITE_DONE)
      {
        // and finally prepend the rest with increasing numbers (starting at 0)
        sqlite3_finalize(stmt);
        DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
                                    "insert into history select imgid, rowid-1, module, operation, op_params, enabled, "
                                    "blendop_params, blendop_version, multi_priority, multi_name from memory.history",
                                    -1, &stmt, NULL);
        sqlite3_step(stmt);
      }
    }
  }
  sqlite3_finalize(stmt);

  //  first time we are loading the image, try to import lightroom .xmp if any
  if (dev->image_loading)
    dt_lightroom_import(dev->image_storage.id, dev, TRUE);

  image->flags |= DT_IMAGE_AUTO_PRESETS_APPLIED | DT_IMAGE_NO_LEGACY_PRESETS;
  dt_pthread_mutex_unlock(&darktable.db_insert);

  // make sure these end up in the image_cache + xmp (sync through here if we set the flag)
  dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_SAFE);
  dt_image_cache_read_release(darktable.image_cache, cimg);
}