static int _write_buffer(const uint32_t key, const void *data, void *user_data) { if(!data) return 1; struct dt_mipmap_buffer_dsc* dsc = (struct dt_mipmap_buffer_dsc*)data; // too small to write. no error, but don't write. if(dsc->width <= 8 && dsc->height <= 8) return 0; _iterate_data_t *d = (_iterate_data_t *)user_data; int written = fwrite(&(d->mip), sizeof(dt_mipmap_size_t), 1, d->f); if(written != 1) return 1; written = fwrite(&key, sizeof(uint32_t), 1, d->f); if(written != 1) return 1; if(d->compression_type) { // write buffer size, wd, ht and the full blob, as it is in memory. const int32_t length = compressed_buffer_size(d->compression_type, dsc->width, dsc->height); written = fwrite(&length, sizeof(int32_t), 1, d->f); if(written != 1) return 1; written = fwrite(&dsc->width, sizeof(int32_t), 1, d->f); if(written != 1) return 1; written = fwrite(&dsc->height, sizeof(int32_t), 1, d->f); if(written != 1) return 1; written = fwrite(dsc+1, sizeof(uint8_t), length, d->f); if(written != length) return 1; } else { dt_mipmap_buffer_t buf; buf.width = dsc->width; buf.height = dsc->height; buf.imgid = get_imgid(key); buf.size = get_size(key); // skip to next 8-byte alignment, for sse buffers. buf.buf = (uint8_t *)(dsc+1); const int cache_quality = dt_conf_get_int("database_cache_quality"); const int32_t length = dt_imageio_jpeg_compress(buf.buf, d->blob, buf.width, buf.height, MIN(100, MAX(10, cache_quality))); written = fwrite(&length, sizeof(int32_t), 1, d->f); if(written != 1) return 1; written = fwrite(d->blob, sizeof(uint8_t), length, d->f); if(written != length) return 1; } return 0; }
static void generate_thumbnail_cache() { const int max_mip = DT_MIPMAP_2; fprintf(stderr, _("creating cache directories\n")); char filename[PATH_MAX] = {0}; for(int k=DT_MIPMAP_0;k<=max_mip;k++) { snprintf(filename, sizeof(filename), "%s.d/%d", darktable.mipmap_cache->cachedir, k); fprintf(stderr, _("creating cache directory '%s'\n"), filename); int mkd = g_mkdir_with_parents(filename, 0750); if(mkd) { fprintf(stderr, _("could not create directory '%s'!\n"), filename); return; } } // some progress counter sqlite3_stmt *stmt; uint64_t image_count = 0, counter = 0; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select count(id) from images", -1, &stmt, 0); if(sqlite3_step(stmt) == SQLITE_ROW) image_count = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); // go through all images: DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select id from images", -1, &stmt, 0); // could only alloc max_mip-1, but would need to detect the special case that max==0. const size_t bufsize = (size_t)4 * darktable.mipmap_cache->max_width[max_mip] * darktable.mipmap_cache->max_height[max_mip]; uint8_t *tmp = (uint8_t *)dt_alloc_align(16, bufsize); if(!tmp) { fprintf(stderr, "couldn't allocate temporary memory!\n"); sqlite3_finalize(stmt); return; } const int cache_quality = MIN(100, MAX(10, dt_conf_get_int("database_cache_quality"))); while(sqlite3_step(stmt) == SQLITE_ROW) { const int32_t imgid = sqlite3_column_int(stmt, 0); // check whether all of these files are already there int all_exist = 1; for(int k=max_mip;k>=DT_MIPMAP_0;k--) { snprintf(filename, sizeof(filename), "%s.d/%d/%d.jpg", darktable.mipmap_cache->cachedir, k, imgid); all_exist &= !access(filename, R_OK); } if(all_exist) goto next; dt_mipmap_buffer_t buf; // get largest thumbnail for this image // this one will take care of itself, we'll just write out the lower thumbs manually: dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, max_mip, DT_MIPMAP_BLOCKING, 'r'); if(buf.width > 8 && buf.height > 8) // don't create for skulls for(int k=max_mip-1;k>=DT_MIPMAP_0;k--) { uint32_t width, height; const int wd = darktable.mipmap_cache->max_width[k]; const int ht = darktable.mipmap_cache->max_height[k]; // use exactly the same mechanism as the cache internally to rescale the thumbnail: dt_iop_flip_and_zoom_8(buf.buf, buf.width, buf.height, tmp, wd, ht, 0, &width, &height); snprintf(filename, sizeof(filename), "%s.d/%d/%d.jpg", darktable.mipmap_cache->cachedir, k, imgid); FILE *f = fopen(filename, "wb"); if(f) { // allocate temp memory: uint8_t *blob = (uint8_t *)malloc(bufsize); if(!blob) goto write_error; const int32_t length = dt_imageio_jpeg_compress(tmp, blob, width, height, cache_quality); assert(length <= bufsize); int written = fwrite(blob, sizeof(uint8_t), length, f); if(written != length) { write_error: unlink(filename); } free(blob); fclose(f); } } dt_mipmap_cache_release(darktable.mipmap_cache, &buf); next: counter ++; fprintf(stderr, "\rimage %lu/%lu (%.02f%%) ", counter, image_count, 100.0*counter/(float)image_count); } dt_free_align(tmp); sqlite3_finalize(stmt); fprintf(stderr, "done \n"); }