English inicio | presentación | artículos | descargas | enlaces

Dcraw con caché y soporte para Rawzor

Añadiendo esta única línea (en el sitio adecuado) al código fuente de dcraw:

#include "rn_cache.c"

conseguimos implementar un sistema de caché para la lectura y decodificación del archivo raw que acelera considerablemente la carga y, de paso, implementamos soporte para archivos raw comprimidos con Rawzor.

Los resultados aplicados a mi colección de raws (tiempos de carga y decodificación en segundos):

dyerware.com


El tiempo conjunto empleado en obtener un revelado rápido (opción -h) para toda mi colección de raws ha pasado de 27,0 a 18,4 segundos, es decir, se ha visto reducido en más de 8 segundos y medio (una mejora de un 32%). A la hora de obtener los thumbnails de un directorio de archivos raw es un tiempo considerable.

No modificar practicamente nada el código de Coffin es importante para poder sacar actualizaciones tan rápido como él saque una nueva versión. Podéis descargar desde aquí binarios de dcraw para varias plataformas con y sin el caché.

Como se ve en la gráfica hay un par de casos en los que el caché aumenta el tiempo de carga. Se trata de los archivos de las Sony comprimidos y los archivos de FinePix. En la versión que liberaré del código (aquí se trataba de ilustrar el asunto), los archivos de estas cámaras no usarán el sistema de caché.

El código del caché, rn_cache.c:

// To the extent possible under law, Manuel Llorens <manuelllorens@gmail.com>
// has waived all copyright and related or neighboring rights to this work.
// This code is licensed under CC0 v1.0, see license information at
// http://creativecommons.org/publicdomain/zero/1.0/

#include "rwz_sdk.h"

// In-memory file struct
typedef struct{
  int id;
  unsigned char *ptr;
  size_t size;
  long int position;
} rn_FILE;

// Gets an rn_FILE pointer from a FILE pointer
rn_FILE *rn_get_rn_FILE(const FILE *stream){
  rn_FILE *mem_stream;

  mem_stream=(rn_FILE *)stream;
  if(mem_stream->id==0x7261776e) return mem_stream; else return NULL;
}

// Replaces fopen function. If the file is opened for binary reading
// it is loaded in memory and a pointer to this memory file is returned
FILE *rn_fopen (const char *filename, const char *mode){
  FILE *stream;
  rn_FILE *mem_stream;
  int rwz_status,rwz_size;
  int tiff_order;
  unsigned char *rwz_buffer;

  // Open the file and return NULL if not success
  stream=fopen(filename,mode);
  if(stream==NULL) return NULL;

  // Only use in-memory file for reading binary files
  if(strcmp(mode,"rb")) return stream;  

  // Create a new rn_FILE struct
  mem_stream=(rn_FILE *)malloc(sizeof(rn_FILE));
  merror(mem_stream,"rawness rn_fopen");

  // Get file length and reserve memory
  fseek(stream,0,SEEK_END);
  mem_stream->size=ftell(stream);

  // If size is 0 return NULL
  if(mem_stream->size==0) return NULL;

  // Alloc memory for the in-memory file
  mem_stream->ptr=(unsigned char *)malloc(mem_stream->size);
  merror(mem_stream->ptr,"rawness rn_fopen");

  // Read the full file into memory
  fseek(stream,0,SEEK_SET);
  fread(mem_stream->ptr,mem_stream->size,1,stream);

  // Close the file
  fclose(stream);

  // ********************
  // RAWZOR decompression
  // Is rawzor file?
  rwz_status=m_rwz_check((char *)mem_stream->ptr,mem_stream->size,&rwz_size);
  if (!rwz_status){
    // Yes!
    if (verbose)
      fprintf(stderr,_("Decompressing Rawzor file...n"),rwz_status); 

    // Decompress file
    rwz_buffer=(unsigned char *)malloc(rwz_size);
    merror(mem_stream->ptr,"rawness rn_fopen");
    rwz_status=m_rwz_decompress((char *)mem_stream->ptr,mem_stream->size,(char *)rwz_buffer,rwz_size);
    if (rwz_status){
      // Wrong rwz file
      fprintf(stderr,_("Not a valid Rawzor filen"),rwz_status);
    }else{
      // Rawzor file decompressed
      free (mem_stream->ptr);
      mem_stream->ptr=rwz_buffer;
      mem_stream->size=rwz_size;
    }
  }
  // Yes, but wrong version
  if (rwz_status==2){
    fprintf(stderr,_("The input rwz file needs a newer version of Rawzor SDKn"));
    return NULL;
  }
  // ********************

  // Return the rn_FILE
  mem_stream->id=0x7261776e;
  mem_stream->position=0;
  return (FILE *)mem_stream;
}

// Replaces fclose function. If the file pointer is a memory pointer
// it releases the memory. The real file was closed in fopen
int rn_fclose (FILE *stream){
  rn_FILE *mem_stream;

  if(stream!=NULL){
    // Check if the FILE pointer is a in-memory pointer or not
    // if not call original fclose and return
    mem_stream=rn_get_rn_FILE(stream);
    if(mem_stream==NULL) return fclose(stream);

    // Release the in-memory file
    free (mem_stream->ptr);
    free (mem_stream);

    // Return success
    return 0;
  }else{
    // Return fail
    return -1;
  }
}

// Replaces fread function. It copies from the memory buffer instead
// of reading the file from disk
size_t rn_fread (void *ptr, size_t size, size_t count, FILE *stream){
  rn_FILE *mem_stream;

  // Check if the FILE pointer is a in-memory pointer or not
  // if not call original fclose and return
  mem_stream=rn_get_rn_FILE(stream);
  if(mem_stream==NULL) return fread(ptr,size,count,stream);

  // Calculate the correct size (do not overflow)
  if(size*count>mem_stream->size-mem_stream->position){
    size=mem_stream->size-mem_stream->position;
  }else{
    size*=count;
  }

  // Do the memcpy from the in-memory file
  memcpy(ptr,mem_stream->ptr+mem_stream->position,size);

  // Increase position
  mem_stream->position+=size;
  return size;
}

// Replaces getc function. It gets the int in the pointer position
int rn_getc (FILE *stream){
  rn_FILE *mem_stream;
  int r;

  // Check if the FILE pointer is a in-memory pointer or not
  // if not call original getc and return
  mem_stream=rn_get_rn_FILE(stream);
  if(mem_stream==NULL) return getc(stream);

  // Get int value in current position and return
  if(mem_stream->position<=mem_stream->size){
    r=(mem_stream->ptr+mem_stream->position)[0];
    mem_stream->position++;
    return r;
  }else return EOF;
}

// Replaces feof function. If checks for in-memory end of file
int rn_feof (FILE *stream){
  rn_FILE *mem_stream;  

  // Check if the FILE pointer is a in-memory pointer or not
  // if not call original feof and return
  mem_stream=rn_get_rn_FILE(stream);
  if(mem_stream==NULL) return feof(stream);

  // Check and return end of file
  if(mem_stream->position<mem_stream->size) return 0; else return EOF;
}

long int rn_fseek (FILE *stream, long int offset, int origin){
  rn_FILE *mem_stream;  

  // Check if the FILE pointer is a in-memory pointer or not
  // if not call original fseek and return
  mem_stream=rn_get_rn_FILE(stream);
  if(mem_stream==NULL) return fseek(stream,offset,origin);

  // Calculate the new position
  switch(origin){
    case SEEK_SET:
      mem_stream->position=offset;
      break;
    case SEEK_CUR:
      mem_stream->position+=offset;
      break;
    case SEEK_END:
      mem_stream->position=mem_stream->size+offset;
  }

  // Check the new position
  if(mem_stream->position<mem_stream->size) return 0; else return EOF;
}

long int rn_ftell (FILE *stream){
 rn_FILE *mem_stream;  

  // Check if the FILE pointer is a in-memory pointer or not
  // if not call original fseek and return
  mem_stream=rn_get_rn_FILE(stream);
  if(mem_stream==NULL) return ftell(stream);

  // Return position
  return mem_stream->position;
}

// This function is intended to work with ONLY ONE argument, as
// original Coffin's code only uses it that way. If you need to
// call fscanf with a real file and more than one argument, you
// must use real_fscanf instead.
//
// Beware it will neither check for file EOF.
int rn_fscanf(FILE *stream, const char *format, void *ptr){
  rn_FILE *mem_stream;  

  // Check if the FILE pointer is a in-memory pointer or not
  // if not call original fscanf with one argument and return
  mem_stream=rn_get_rn_FILE(stream);
  if(mem_stream==NULL) return fscanf(stream,format,ptr);

  // Use sscanf instead of fscanf
  sscanf((const char *)mem_stream->ptr+mem_stream->position,format,ptr);
  return 1;
}

char *rn_fgets(char *str, int n, FILE *stream){
  rn_FILE *mem_stream;
  int i;

  // Check if the FILE pointer is a in-memory pointer or not
  // if not call original fgets and return
  mem_stream=rn_get_rn_FILE(stream);
  if(mem_stream==NULL) return fgets(str,n,stream);

  // Check for n size
  if(mem_stream->position+n>mem_stream->size) n=mem_stream->size-mem_stream->position;

  // Get the string
  i=0;
  while(i<n){
    str[i]=mem_stream->ptr[mem_stream->position++];
    if((str[i]==0x13)||(str[i]==0x00)) break;
    i++;
  }
  mem_stream->position--;
  str[i]=0x00;

  return str;
}

// Define new file functions for in-memory raw file opening
// This is needed for in-memory rawzor support
#define real_fscanf fscanf

#define fopen       rn_fopen
#define fclose      rn_fclose
#define fread       rn_fread
#define getc        rn_getc
#define fgetc       rn_getc
#define feof        rn_feof
#define fseek       rn_fseek
#define ftell       rn_ftell
#define fscanf      rn_fscanf
#define fgets       rn_fgets

Si quieres descargar una versión de dcraw con estas mejoras, la tienes aquí.

VN:F [1.9.13_1145]
Rating: 0.0/5 (0 votes cast)

Related posts:

  1. Wildness: procesando por lotes con dcraw para Windows
  2. Descarga de binarios de dcraw para Windows
  3. Extender dcraw: raws sintéticos y stacking raw
  4. Descarga de binarios de dcraw para Linux
  5. Algoritmos de interpolación para cámaras cuatro tercios y micro 4/3

10 comentarios. Deja un comentario »

RSS feed para los comentarios de esta entrada. TrackBack URL

Deja un comentario