Skip to content

Commit

Permalink
Discontinued 64-bit floating point support
Browse files Browse the repository at this point in the history
Supporting both 32 and 64 is too much complexity, for little or no benefit.
  • Loading branch information
jsummers committed Feb 22, 2014
1 parent 3037443 commit db81196
Show file tree
Hide file tree
Showing 18 changed files with 38 additions and 229 deletions.
2 changes: 1 addition & 1 deletion changelog.txt
@@ -1,5 +1,5 @@
Unreleased changes
- (none)
- Discontinued 64-bit floating point precision support.

Version 1.2.0 - 16 Feb 2014
- Switched to MIT-style license.
Expand Down
11 changes: 1 addition & 10 deletions readme.txt
Expand Up @@ -189,7 +189,7 @@ Options:
output image. Valid values for <n>:
"8" is the default for most formats.
"16" is supported for PNG and TIFF formats.
"32" and "64" are used with MIFF format (floating point).
"32" is used with MIFF format (floating point).
Other depths are supported in some special cases. Use with caution -- this
can be useful, but it may not do what you expect, and may disable
optimizations. Consider whether you should use -cc instead.
Expand Down Expand Up @@ -736,15 +736,6 @@ Options:
WebP-style quality setting to use if a WebP file is written. This is on a
scale from 0 to 100. Default is 80.

-precision <n>
The minimum size, in bits, of a floating point number used to represent a
sample. Default is 64. Setting this to 32 will save memory, with minimal
reduction in accuracy. The effect on performance is not clear.

Generally speaking, 64-bit floating point will be used for all calculations,
regardless of the -precision setting. If -precision is set to 32, 32-bit
floating point will be used when storing large amounts of data in memory.

-encoding <encoding>
Set the encoding used for text output (informational and error messages).
This is usually unnecessary, because IW can usually figure out what
Expand Down
6 changes: 1 addition & 5 deletions src/imagew-api.c
Expand Up @@ -246,7 +246,6 @@ IW_IMPL(struct iw_context*) iw_create_context(struct iw_init_params *params)
}

ctx->max_malloc = IW_DEFAULT_MAX_MALLOC;
ctx->precision = 64;
ctx->max_width = ctx->max_height = IW_DEFAULT_MAX_DIMENSION;
default_resize_settings(&ctx->resize_settings[IW_DIMENSION_H]);
default_resize_settings(&ctx->resize_settings[IW_DIMENSION_V]);
Expand Down Expand Up @@ -820,9 +819,6 @@ IW_IMPL(void) iw_set_value(struct iw_context *ctx, int code, int n)
case IW_VAL_MAX_HEIGHT:
ctx->max_height = n;
break;
case IW_VAL_PRECISION:
ctx->precision = (n<=32)?32:64;
break;
case IW_VAL_NO_BKGD_LABEL:
ctx->req.suppress_output_bkgd_label = n;
break;
Expand Down Expand Up @@ -936,7 +932,7 @@ IW_IMPL(int) iw_get_value(struct iw_context *ctx, int code)
ret = ctx->max_height;
break;
case IW_VAL_PRECISION:
ret = ctx->precision;
ret = 32;
break;
case IW_VAL_NO_BKGD_LABEL:
ret = ctx->req.suppress_output_bkgd_label;
Expand Down
4 changes: 1 addition & 3 deletions src/imagew-cmd.c
Expand Up @@ -101,7 +101,6 @@ struct params_struct {
struct resize_blur resize_blur_y;
int bestfit;
int bestfit_option;
int precision;
int depth; // Overall depth
int sample_type;
int channel_depth[5]; // Per-channeltype depth, indexed by IW_CHANNELTYPE
Expand Down Expand Up @@ -1103,7 +1102,6 @@ static int iwcmd_run(struct params_struct *p)
iw_set_random_seed(ctx,p->randomize, p->random_seed);
}

if(p->precision) iw_set_value(ctx,IW_VAL_PRECISION,p->precision);
if(p->sample_type>=0) iw_set_value(ctx,IW_VAL_OUTPUT_SAMPLE_TYPE,p->sample_type);
if(p->no_gamma) iw_set_value(ctx,IW_VAL_DISABLE_GAMMA,1);
if(p->intclamp) iw_set_value(ctx,IW_VAL_INT_CLAMP,1);
Expand Down Expand Up @@ -2487,7 +2485,7 @@ static int process_option_arg(struct params_struct *p, struct parsestate_struct
if(ret<0) return 0;
break;
case PT_PRECISION:
p->precision = iwcmd_parse_int(v);
// This option is obsolete.
break;
case PT_DEPTH:
ret=iwcmd_read_depth(p,v);
Expand Down
8 changes: 0 additions & 8 deletions src/imagew-internals.h
Expand Up @@ -176,17 +176,9 @@ struct iw_context {
int use_count;
unsigned int output_profile;

// Precision of intermediate samples, 32 (=32) or 64 (=whatever IW_SAMPLE is)
int precision;

iw_mallocfn_type mallocfn;
iw_freefn_type freefn;

// The "64" data is only actually only 64-bit if IW_SAMPLE is 64-bit.
IW_SAMPLE *intermediate64;
IW_SAMPLE *intermediate_alpha64;
IW_SAMPLE *final_alpha64;

iw_float32 *intermediate32;
iw_float32 *intermediate_alpha32;
iw_float32 *final_alpha32;
Expand Down
150 changes: 25 additions & 125 deletions src/imagew-main.c
Expand Up @@ -266,9 +266,7 @@ static IW_SAMPLE get_raw_sample(struct iw_context *ctx,
if(ctx->img1.sampletype==IW_SAMPLETYPE_FLOATINGPOINT) {
int rx, ry;
translate_coords(ctx,x,y,&rx,&ry);
if(ctx->img1.bit_depth==64) {
return get_raw_sample_flt64(ctx,rx,ry,channel);
}
if(ctx->img1.bit_depth!=32) return 0.0;
return get_raw_sample_flt32(ctx,rx,ry,channel);
}

Expand Down Expand Up @@ -437,36 +435,6 @@ static IW_INLINE void put_raw_sample_flt32(struct iw_context *ctx, double s,
}
}

// s is from 0.0 to 1.0
static IW_INLINE void put_raw_sample_flt64(struct iw_context *ctx, double s,
int x, int y, int channel)
{
// !!! Portability warning: Using a union in this way may be nonportable,
// and/or may violate strict-aliasing rules.
union su_union {
iw_byte c[8];
iw_float64 f;
} volatile su;
int i;
size_t pos;

su.f = (iw_float32)s;
pos = y*ctx->img2.bpr + (ctx->img2_numchannels*x + channel)*8;

for(i=0;i<8;i++) {
ctx->img2.pixels[pos+i] = su.c[i];
}
}

static void put_raw_sample_flt(struct iw_context *ctx, double s,
int x, int y, int channel)
{
switch(ctx->img2.bit_depth) {
case 32: put_raw_sample_flt32(ctx,s,x,y,channel); break;
case 64: put_raw_sample_flt64(ctx,s,x,y,channel); break;
}
}

static IW_SAMPLE linear_to_x_sample(IW_SAMPLE samp_lin, const struct iw_csdescr *csdescr)
{
if(samp_lin > 0.999999999) {
Expand Down Expand Up @@ -671,7 +639,7 @@ static int get_nearest_valid_colors(struct iw_context *ctx, IW_SAMPLE samp_lin,
static void put_sample_convert_from_linear_flt(struct iw_context *ctx, IW_SAMPLE samp_lin,
int x, int y, int channel, const struct iw_csdescr *csdescr)
{
put_raw_sample_flt(ctx,(double)samp_lin,x,y,channel);
put_raw_sample_flt32(ctx,(double)samp_lin,x,y,channel);
}

static double get_final_sample_using_nc_tbl(struct iw_context *ctx, IW_SAMPLE samp_lin)
Expand Down Expand Up @@ -943,16 +911,10 @@ static int iw_process_cols_to_intermediate(struct iw_context *ctx, int channel,
// The intermediate pixels are in ctx->out_pix. Copy them to the intermediate array.
for(j=0;j<ctx->intermed_canvas_height;j++) {
if(is_alpha_channel) {
if(ctx->precision==64)
ctx->intermediate_alpha64[((size_t)j)*ctx->intermed_canvas_width + i] = out_pix[j];
else
ctx->intermediate_alpha32[((size_t)j)*ctx->intermed_canvas_width + i] = (iw_float32)out_pix[j];
ctx->intermediate_alpha32[((size_t)j)*ctx->intermed_canvas_width + i] = (iw_float32)out_pix[j];
}
else {
if(ctx->precision==64)
ctx->intermediate64[((size_t)j)*ctx->intermed_canvas_width + i] = out_pix[j];
else
ctx->intermediate32[((size_t)j)*ctx->intermed_canvas_width + i] = (iw_float32)out_pix[j];
ctx->intermediate32[((size_t)j)*ctx->intermed_canvas_width + i] = (iw_float32)out_pix[j];
}
}
}
Expand Down Expand Up @@ -1010,18 +972,13 @@ static int iw_process_rows_intermediate_to_final(struct iw_context *ctx, int int
is_alpha_channel = (int_ci->channeltype==IW_CHANNELTYPE_ALPHA);
bkgd_has_transparency = iw_bkgd_has_transparency(ctx);

if(ctx->precision!=64) {
inpix_tofree = (IW_SAMPLE*)iw_malloc(ctx, num_in_pix * sizeof(IW_SAMPLE));
in_pix = inpix_tofree;
}
inpix_tofree = (IW_SAMPLE*)iw_malloc(ctx, num_in_pix * sizeof(IW_SAMPLE));
in_pix = inpix_tofree;

if(!is_alpha_channel || ctx->precision!=64) {
// We need an output buffer, except if this is a 64-bit alpha channel.
// (For 64-bit alpha samples, we'll use ctx->final_alpha directly.)
outpix_tofree = (IW_SAMPLE*)iw_malloc(ctx, num_out_pix * sizeof(IW_SAMPLE));
if(!outpix_tofree) goto done;
out_pix = outpix_tofree;
}
// We need an output buffer.
outpix_tofree = (IW_SAMPLE*)iw_malloc(ctx, num_out_pix * sizeof(IW_SAMPLE));
if(!outpix_tofree) goto done;
out_pix = outpix_tofree;

// Decide if the 'nearest color table' optimization can be used
if(ctx->nearest_color_table && !is_alpha_channel &&
Expand Down Expand Up @@ -1075,31 +1032,14 @@ static int iw_process_rows_intermediate_to_final(struct iw_context *ctx, int int
// ctx->in_pix already points to), or point ctx->in_pix directly to the
// intermediate data.
if(is_alpha_channel) {
if(inpix_tofree) {
// This will only happen if the precision is 32
for(i=0;i<num_in_pix;i++) {
inpix_tofree[i] = ctx->intermediate_alpha32[((size_t)j)*ctx->intermed_canvas_width+i];
}
}
else {
in_pix = &ctx->intermediate_alpha64[((size_t)j)*ctx->intermed_canvas_width];
for(i=0;i<num_in_pix;i++) {
inpix_tofree[i] = ctx->intermediate_alpha32[((size_t)j)*ctx->intermed_canvas_width+i];
}
}
else {
if(inpix_tofree) {
for(i=0;i<num_in_pix;i++) {
inpix_tofree[i] = ctx->intermediate32[((size_t)j)*ctx->intermed_canvas_width+i];
}
for(i=0;i<num_in_pix;i++) {
inpix_tofree[i] = ctx->intermediate32[((size_t)j)*ctx->intermed_canvas_width+i];
}
else {
in_pix = &ctx->intermediate64[((size_t)j)*ctx->intermed_canvas_width];
}
}

// If needed, point ctx->out_pix to the right place in the output data.
// (Otherwise, it's already pointing the temporary "outpix" buffer.)
if(!outpix_tofree) {
out_pix = &ctx->final_alpha64[((size_t)j)*ctx->img2.width];
}

// Resize ctx->in_pix to ctx->out_pix.
Expand Down Expand Up @@ -1145,10 +1085,7 @@ static int iw_process_rows_intermediate_to_final(struct iw_context *ctx, int int

if(int_ci->need_unassoc_alpha_processing) {
// Convert color samples back to unassociated alpha.
if(ctx->precision==64)
alphasamp = ctx->final_alpha64[((size_t)j)*ctx->img2.width + i];
else
alphasamp = ctx->final_alpha32[((size_t)j)*ctx->img2.width + i];
alphasamp = ctx->final_alpha32[((size_t)j)*ctx->img2.width + i];

if(alphasamp!=0.0) {
tmpsamp /= alphasamp;
Expand Down Expand Up @@ -1388,9 +1325,6 @@ static int iw_process_internal(struct iw_context *ctx)
// A linear color-correction descriptor to use with alpha channels.
struct iw_csdescr csdescr_linear;

ctx->intermediate64=NULL;
ctx->intermediate_alpha64=NULL;
ctx->final_alpha64=NULL;
ctx->intermediate32=NULL;
ctx->intermediate_alpha32=NULL;
ctx->final_alpha32=NULL;
Expand All @@ -1406,17 +1340,9 @@ static int iw_process_internal(struct iw_context *ctx)
goto done;
}

if(ctx->precision==64) {
ctx->intermediate64 = (IW_SAMPLE*)iw_malloc_large(ctx, ctx->intermed_canvas_width * ctx->intermed_canvas_height, sizeof(IW_SAMPLE));
if(!ctx->intermediate64) {
goto done;
}
}
else {
ctx->intermediate32 = (iw_float32*)iw_malloc_large(ctx, ctx->intermed_canvas_width * ctx->intermed_canvas_height, sizeof(iw_float32));
if(!ctx->intermediate32) {
goto done;
}
ctx->intermediate32 = (iw_float32*)iw_malloc_large(ctx, ctx->intermed_canvas_width * ctx->intermed_canvas_height, sizeof(iw_float32));
if(!ctx->intermediate32) {
goto done;
}

if(ctx->uses_errdiffdither) {
Expand All @@ -1434,25 +1360,13 @@ static int iw_process_internal(struct iw_context *ctx)

// If an alpha channel is present, we have to process it first.
if(IW_IMGTYPE_HAS_ALPHA(ctx->intermed_imgtype)) {
if(ctx->precision==64) {
ctx->intermediate_alpha64 = (IW_SAMPLE*)iw_malloc_large(ctx, ctx->intermed_canvas_width * ctx->intermed_canvas_height, sizeof(IW_SAMPLE));
if(!ctx->intermediate_alpha64) {
goto done;
}
ctx->final_alpha64 = (IW_SAMPLE*)iw_malloc_large(ctx, ctx->img2.width * ctx->img2.height, sizeof(IW_SAMPLE));
if(!ctx->final_alpha64) {
goto done;
}
ctx->intermediate_alpha32 = (iw_float32*)iw_malloc_large(ctx, ctx->intermed_canvas_width * ctx->intermed_canvas_height, sizeof(iw_float32));
if(!ctx->intermediate_alpha32) {
goto done;
}
else {
ctx->intermediate_alpha32 = (iw_float32*)iw_malloc_large(ctx, ctx->intermed_canvas_width * ctx->intermed_canvas_height, sizeof(iw_float32));
if(!ctx->intermediate_alpha32) {
goto done;
}
ctx->final_alpha32 = (iw_float32*)iw_malloc_large(ctx, ctx->img2.width * ctx->img2.height, sizeof(iw_float32));
if(!ctx->final_alpha32) {
goto done;
}
ctx->final_alpha32 = (iw_float32*)iw_malloc_large(ctx, ctx->img2.width * ctx->img2.height, sizeof(iw_float32));
if(!ctx->final_alpha32) {
goto done;
}

if(!iw_process_one_channel(ctx,ctx->intermed_alpha_channel_index,&csdescr_linear,&csdescr_linear)) goto done;
Expand All @@ -1476,9 +1390,6 @@ static int iw_process_internal(struct iw_context *ctx)
retval=1;

done:
if(ctx->intermediate64) { iw_free(ctx,ctx->intermediate64); ctx->intermediate64=NULL; }
if(ctx->intermediate_alpha64) { iw_free(ctx,ctx->intermediate_alpha64); ctx->intermediate_alpha64=NULL; }
if(ctx->final_alpha64) { iw_free(ctx,ctx->final_alpha64); ctx->final_alpha64=NULL; }
if(ctx->intermediate32) { iw_free(ctx,ctx->intermediate32); ctx->intermediate32=NULL; }
if(ctx->intermediate_alpha32) { iw_free(ctx,ctx->intermediate_alpha32); ctx->intermediate_alpha32=NULL; }
if(ctx->final_alpha32) { iw_free(ctx,ctx->final_alpha32); ctx->final_alpha32=NULL; }
Expand Down Expand Up @@ -1558,18 +1469,7 @@ static void decide_output_bit_depth(struct iw_context *ctx)

if(ctx->img2.sampletype==IW_SAMPLETYPE_FLOATINGPOINT) {
// Floating point output.
if(ctx->req.output_depth<=0) {
// An output_depth_req of 0 means the caller did not set it.
// The default is to use the maximum useful depth, which is the
// minimum of ctx->precision and the number of bits in IW_SAMPLE.
ctx->img2.bit_depth = (iw_get_sample_size()<=4) ? 32 : ctx->precision;
}
else if(ctx->req.output_depth>=1 && ctx->req.output_depth<=32) {
ctx->img2.bit_depth=32;
}
else {
ctx->img2.bit_depth=64;
}
ctx->img2.bit_depth=32;
return;
}

Expand Down

0 comments on commit db81196

Please sign in to comment.