SANE_Status sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action, void *val, SANE_Int *info) { Tamarack_Scanner *s = handle; SANE_Status status; SANE_Word cap; if (info) *info = 0; if (s->scanning) return SANE_STATUS_DEVICE_BUSY; if (option >= NUM_OPTIONS) return SANE_STATUS_INVAL; cap = s->opt[option].cap; if (!SANE_OPTION_IS_ACTIVE (cap)) return SANE_STATUS_INVAL; if (action == SANE_ACTION_GET_VALUE) { switch (option) { /* word options: */ case OPT_PREVIEW: case OPT_GRAY_PREVIEW: case OPT_RESOLUTION: case OPT_TL_X: case OPT_TL_Y: case OPT_BR_X: case OPT_BR_Y: case OPT_NUM_OPTS: case OPT_TRANS: case OPT_BRIGHTNESS: case OPT_CONTRAST: case OPT_THRESHOLD: #if 0 case OPT_CUSTOM_GAMMA: #endif *(SANE_Word *) val = s->val[option].w; return SANE_STATUS_GOOD; #if 0 /* word-array options: */ case OPT_GAMMA_VECTOR: case OPT_GAMMA_VECTOR_R: case OPT_GAMMA_VECTOR_G: case OPT_GAMMA_VECTOR_B: memcpy (val, s->val[option].wa, s->opt[option].size); return SANE_STATUS_GOOD; #endif /* string options: */ case OPT_MODE: strcpy (val, s->val[option].s); return SANE_STATUS_GOOD; } } else if (action == SANE_ACTION_SET_VALUE) { if (!SANE_OPTION_IS_SETTABLE (cap)) return SANE_STATUS_INVAL; status = constrain_value (s, option, val, info); if (status != SANE_STATUS_GOOD) return status; switch (option) { /* (mostly) side-effect-free word options: */ case OPT_RESOLUTION: case OPT_TL_X: case OPT_TL_Y: case OPT_BR_X: case OPT_BR_Y: if (info) *info |= SANE_INFO_RELOAD_PARAMS; /* fall through */ case OPT_PREVIEW: case OPT_GRAY_PREVIEW: case OPT_BRIGHTNESS: case OPT_CONTRAST: case OPT_THRESHOLD: case OPT_TRANS: s->val[option].w = *(SANE_Word *) val; return SANE_STATUS_GOOD; #if 0 /* side-effect-free word-array options: */ case OPT_GAMMA_VECTOR: case OPT_GAMMA_VECTOR_R: case OPT_GAMMA_VECTOR_G: case OPT_GAMMA_VECTOR_B: memcpy (s->val[option].wa, val, s->opt[option].size); return SANE_STATUS_GOOD; /* options with side-effects: */ case OPT_CUSTOM_GAMMA: w = *(SANE_Word *) val; if (w == s->val[OPT_CUSTOM_GAMMA].w) return SANE_STATUS_GOOD; /* no change */ s->val[OPT_CUSTOM_GAMMA].w = w; if (w) { s->mode = make_mode (s->val[OPT_MODE].s); if (s->mode == GREYSCALE) { s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; } else if (s->mode == TRUECOLOR) { s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE; } } else { s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; } if (info) *info |= SANE_INFO_RELOAD_OPTIONS; return SANE_STATUS_GOOD; #endif case OPT_MODE: { if (s->val[option].s) free (s->val[option].s); s->val[option].s = strdup (val); s->mode = make_mode (s->val[OPT_MODE].s); if (info) *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; s->opt[OPT_BRIGHTNESS].cap |= SANE_CAP_INACTIVE; s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE; s->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE; #if 0 s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; #endif if (strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) == 0) s->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE; else { s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE; s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE; } #if 0 if (!binary) s->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE; if (s->val[OPT_CUSTOM_GAMMA].w) { if (strcmp (val, SANE_VALUE_SCAN_MODE_GRAY) == 0) s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; else if (strcmp (val, SANE_VALUE_SCAN_MODE_COLOR) == 0) { s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE; } } #endif return SANE_STATUS_GOOD; } } } return SANE_STATUS_INVAL; }
TEST(MathTest, Constrain) { for (int i = 0; i < 1000; i++) { if (i < 250) { EXPECT_EQ(250, constrain_float(i, 250, 500)); EXPECT_EQ(250, constrain_int16(i, 250, 500)); EXPECT_EQ(250, constrain_int32(i, 250, 500)); } else if (i > 500) { EXPECT_EQ(500, constrain_float(i, 250, 500)); EXPECT_EQ(500, constrain_int16(i, 250, 500)); EXPECT_EQ(500, constrain_int32(i, 250, 500)); } else { EXPECT_EQ(i, constrain_float(i, 250, 500)); EXPECT_EQ(i, constrain_int16(i, 250, 500)); EXPECT_EQ(i, constrain_int32(i, 250, 500)); } } for (int i = 0; i <= 1000; i++) { int c = i - 1000; if (c < -250) { EXPECT_EQ(-250, constrain_float(c, -250, -50)); EXPECT_EQ(-250, constrain_int16(c, -250, -50)); EXPECT_EQ(-250, constrain_int32(c, -250, -50)); } else if(c > -50) { EXPECT_EQ(-50, constrain_float(c, -250, -50)); EXPECT_EQ(-50, constrain_int16(c, -250, -50)); EXPECT_EQ(-50, constrain_int32(c, -250, -50)); } else { EXPECT_EQ(c, constrain_float(c, -250, -50)); EXPECT_EQ(c, constrain_int16(c, -250, -50)); EXPECT_EQ(c, constrain_int32(c, -250, -50)); } } for (int i = 0; i <= 2000; i++) { int c = i - 1000; if (c < -250) { EXPECT_EQ(-250, constrain_float(c, -250, 50)); EXPECT_EQ(-250, constrain_int16(c, -250, 50)); EXPECT_EQ(-250, constrain_int32(c, -250, 50)); } else if(c > 50) { EXPECT_EQ(50, constrain_float(c, -250, 50)); EXPECT_EQ(50, constrain_int16(c, -250, 50)); EXPECT_EQ(50, constrain_int32(c, -250, 50)); } else { EXPECT_EQ(c, constrain_float(c, -250, 50)); EXPECT_EQ(c, constrain_int16(c, -250, 50)); EXPECT_EQ(c, constrain_int32(c, -250, 50)); } } EXPECT_EQ(20.0, constrain_value(20.0, 19.9, 20.1)); EXPECT_EQ(20.0, constrain_value(20.0f, 19.9f, 20.1f)); EXPECT_EQ(19.9, constrain_value(19.9, 19.9, 20.1)); EXPECT_EQ(19.9f, constrain_value(19.9f, 19.9f, 20.1f)); EXPECT_EQ(19.9, constrain_value(19.8, 19.9, 20.1)); EXPECT_EQ(19.9f, constrain_value(19.8f, 19.9f, 20.1f)); }