void project_files( const std::string& name, const std::string& method, const std::string& from, index_t fromStride, index_t fromRows, index_t fromCols, int lng1, int lng2, int lat1, int lat2, const std::string& to, index_t toStride, index_t toRows, index_t toCols, index_t x, index_t y, index_t totalWidth, index_t totalHeight ) { boost::shared_ptr<Projection<T> > pProject = getProjection<T>(name); if (!pProject) { Rcpp::stop("Unsupported projection: %s", name); } boost::shared_ptr<Interpolator<T> > pInterp = getInterpolator<T>(method); if (!pInterp) { Rcpp::stop("Unsupported interpolator: %s", method); } // Memory mapped files MMFile<T> from_f(from, boost::interprocess::read_only); MMFile<T> to_f(to, boost::interprocess::read_write); // Grid will help us conveniently offset into mmap by row/col Grid<T> from_g(from_f.begin(), from_f.end(), fromStride, fromRows, fromCols); Grid<T> to_g(to_f.begin(), to_f.end(), toStride, toRows, toCols); project<T>(pProject.get(), pInterp.get(), from_g, lat1, lat2, lng1, lng2, to_g, x, totalWidth, y, totalHeight); }
float modify_alpha(read_info *input_image, int ie_bug) { /* IE6 makes colors with even slightest transparency completely transparent, thus to improve situation in IE, make colors that are less than ~10% transparent completely opaque */ rgb_pixel **input_pixels = (rgb_pixel **)input_image->row_pointers; rgb_pixel *pP; int rows= input_image->height, cols = input_image->width; double gamma = input_image->gamma; float min_opaque_val, almost_opaque_val; if (ie_bug) { min_opaque_val = 238.0/256.0; /* rest of the code uses min_opaque_val rather than checking for ie_bug */ almost_opaque_val = min_opaque_val * 169.0/256.0; verbose_printf(" Working around IE6 bug by making image less transparent...\n"); } else { min_opaque_val = almost_opaque_val = 1; } for(int row = 0; row < rows; ++row) { pP = input_pixels[row]; for(int col = 0; col < cols; ++col, ++pP) { f_pixel px = to_f(gamma, *pP); #ifndef NDEBUG rgb_pixel rgbcheck = to_rgb(gamma, px); if (pP->a && (pP->r != rgbcheck.r || pP->g != rgbcheck.g || pP->b != rgbcheck.b || pP->a != rgbcheck.a)) { fprintf(stderr, "Conversion error: expected %d,%d,%d,%d got %d,%d,%d,%d\n", pP->r,pP->g,pP->b,pP->a, rgbcheck.r,rgbcheck.g,rgbcheck.b,rgbcheck.a); return -1; } #endif /* set all completely transparent colors to black */ if (!pP->a) { *pP = (rgb_pixel){0,0,0,pP->a}; } /* ie bug: to avoid visible step caused by forced opaqueness, linearily raise opaqueness of almost-opaque colors */ else if (pP->a < 255 && px.a > almost_opaque_val) { assert((min_opaque_val-almost_opaque_val)>0); float al = almost_opaque_val + (px.a-almost_opaque_val) * (1-almost_opaque_val) / (min_opaque_val-almost_opaque_val); if (al > 1) al = 1; px.a = al; pP->a = to_rgb(gamma, px).a; } } } return min_opaque_val; }
void set_palette(write_info *output_image, colormap *map) { for (int x = 0; x < map->colors; ++x) { rgb_pixel px = to_rgb(output_image->gamma, map->palette[x].acolor); map->palette[x].acolor = to_f(output_image->gamma, px); /* saves rounding error introduced by to_rgb, which makes remapping & dithering more accurate */ output_image->palette[x].red = px.r; output_image->palette[x].green = px.g; output_image->palette[x].blue = px.b; output_image->trans[x] = px.a; } }
float remap_to_palette(read_info *input_image, write_info *output_image, colormap *map, float min_opaque_val, int ie_bug) { rgb_pixel **input_pixels = (rgb_pixel **)input_image->row_pointers; unsigned char **row_pointers = output_image->row_pointers; int rows = input_image->height, cols = input_image->width; double gamma = input_image->gamma; int remapped_pixels=0; float remapping_error=0; int transparent_ind = best_color_index((f_pixel){0,0,0,0}, map, min_opaque_val, NULL); f_pixel average_color[map->colors]; float average_color_count[map->colors]; viter_init(map, average_color, average_color_count, NULL, NULL); for (int row = 0; row < rows; ++row) { for(int col = 0; col < cols; ++col) { f_pixel px = to_f(gamma, input_pixels[row][col]); int match; if (px.a < 1.0/256.0) { match = transparent_ind; } else { float diff; match = best_color_index(px, map,min_opaque_val, &diff); remapped_pixels++; remapping_error += diff; } row_pointers[row][col] = match; viter_update_color(px, 1.0, map, match, average_color, average_color_count, NULL, NULL); } } viter_finalize(map, average_color, average_color_count); return remapping_error / MAX(1,remapped_pixels); }
Vector2 Vector2i::GetNormalized(void) const { Vector2 floats = to_f(); floats.Normalize(); return floats; }
Vector3 Vector3i::GetNormalized() { Vector3 floats = to_f(); floats.Normalize(); return floats; }
int Number::compare(const Number& num) const { #ifndef PMP_DISABLE_VECTOR if (is_v() || num.is_v()) { bool comparisons[3]; compare(num, comparisons); if (comparisons[0]) return -1; else if (comparisons[1]) return 0; else if (comparisons[2]) return 1; else return -2; } #endif floating_type f; switch (type()) { case Number::INTEGER: switch (num.type()) { case Number::INTEGER: return get_i().compare(num.get_i()); case Number::FLOATING: f = to_f(); return f.compare(num.get_f()); case Number::RATIONAL: f = to_f(); return f.compare(num.to_f()); default: assert(0); return 0; } case Number::FLOATING: switch (num.type()) { case Number::INTEGER: f = num.to_f(); return get_f().compare(f); case Number::FLOATING: return get_f().compare(num.get_f()); case Number::RATIONAL: return get_f().compare(num.to_f()); default: assert(0); return 0; } case Number::RATIONAL: switch (num.type()) { case Number::INTEGER: f = num.to_f(); return to_f().compare(f); case Number::FLOATING: return to_f().compare(num.get_f()); case Number::RATIONAL: return to_f().compare(num.to_f()); default: assert(0); return 0; } default: assert(0); return 0; } }
Number& Number::operator+=(const Number& num) { #ifndef PMP_DISABLE_VECTOR if (is_v() || num.is_v()) { vector_type vec; for (size_t i = 0; i < size(); ++i) { for (size_t j = 0; j < num.size(); ++j) { Number tmp((*this)[i]); tmp += num[j]; vec.push_back(tmp); } } assign(vec); return *this; } #endif // ndef PMP_DISABLE_VECTOR integer_type i; floating_type f; rational_type r; switch (type()) { case Number::INTEGER: switch (num.type()) { case Number::INTEGER: i = get_i(); i += num.get_i(); assign(i); break; case Number::FLOATING: f = to_f(); f += num.get_f(); assign(f); break; case Number::RATIONAL: r = to_r(); r += num.get_r(); assign(r); break; default: assert(0); break; } break; case Number::FLOATING: switch (num.type()) { case Number::INTEGER: f = get_f(); f += num.to_f(); assign(f); break; case Number::FLOATING: f = get_f(); f += num.get_f(); assign(f); break; case Number::RATIONAL: f = get_f(); f += num.to_f(); assign(f); break; default: assert(0); break; } break; case Number::RATIONAL: switch (num.type()) { case Number::INTEGER: r = get_r(); r += num.to_r(); assign(r); break; case Number::FLOATING: f = to_f(); f += num.get_f(); assign(f); break; case Number::RATIONAL: r = get_r(); r += num.get_r(); assign(r); break; default: assert(0); break; } break; default: assert(0); break; } return *this; }
Number& Number::operator%=(const Number& num) { #ifndef PMP_DISABLE_VECTOR if (is_v() || num.is_v()) { vector_type vec; for (size_t i = 0; i < size(); ++i) { for (size_t j = 0; j < num.size(); ++j) { Number tmp((*this)[i]); tmp %= num[j]; vec.push_back(tmp); } } assign(vec); return *this; } #endif integer_type i; floating_type f; rational_type r; switch (type()) { case Number::INTEGER: switch (num.type()) { case Number::INTEGER: i = get_i(); i %= num.get_i(); assign(i); break; case Number::FLOATING: f = to_f(); f = b_mp::fmod(f, num.get_f()); assign(f); break; default: assert(0); break; } break; case Number::FLOATING: switch (num.type()) { case Number::INTEGER: f = get_f(); f = b_mp::fmod(f, static_cast<floating_type>(num.get_i())); assign(f); break; case Number::FLOATING: f = get_f(); f = b_mp::fmod(f, num.get_f()); assign(f); break; default: assert(0); break; } break; default: assert(0); break; } return *this; }
Number& Number::operator/=(const Number& num) { #ifndef PMP_DISABLE_VECTOR if (is_v() || num.is_v()) { vector_type vec; for (size_t i = 0; i < size(); ++i) { for (size_t j = 0; j < num.size(); ++j) { Number tmp((*this)[i]); tmp /= num[j]; vec.push_back(tmp); } } assign(vec); return *this; } #endif integer_type i; floating_type f; rational_type r; switch (type()) { case Number::INTEGER: switch (num.type()) { case Number::INTEGER: if (s_intdiv_type == Number::INTEGER) { i = get_i(); i /= num.get_i(); assign(i); } else if (s_intdiv_type == Number::FLOATING) { if (b_mp::fmod(to_f(), num.to_f()) != 0) { f = to_f(); f /= num.to_f(); assign(f); } else { i = get_i(); i /= num.get_i(); assign(i); } } else if (s_intdiv_type == Number::RATIONAL) { r = rational_type(get_i(), num.get_i()); assign(r); } else { assert(0); } break; case Number::FLOATING: f = to_f(); f /= num.get_f(); assign(f); break; case Number::RATIONAL: r = to_r(); r /= num.get_r(); assign(r); break; default: assert(0); break; } break; case Number::FLOATING: switch (num.type()) { case Number::INTEGER: f = get_f(); f /= num.to_f(); assign(f); break; case Number::FLOATING: f = get_f(); f /= num.get_f(); assign(f); break; case Number::RATIONAL: f = get_f(); f /= num.to_f(); assign(f); break; default: assert(0); break; } break; case Number::RATIONAL: switch (num.type()) { case Number::INTEGER: r = get_r(); r /= num.to_r(); assign(r); break; case Number::FLOATING: f = to_f(); f /= num.get_f(); assign(f); break; case Number::RATIONAL: r = get_r(); r /= num.get_r(); assign(r); break; default: assert(0); break; } break; default: assert(0); break; } return *this; }
float remap_to_palette_floyd(read_info *input_image, write_info *output_image, const colormap *map, float min_opaque_val, int ie_bug) { rgb_pixel **input_pixels = (rgb_pixel **)input_image->row_pointers; unsigned char **row_pointers = output_image->row_pointers; int rows = input_image->height, cols = input_image->width; double gamma = input_image->gamma; int remapped_pixels=0; float remapping_error=0; const colormap_item *acolormap = map->palette; int ind=0; int transparent_ind = best_color_index((f_pixel){0,0,0,0}, map, min_opaque_val, NULL); f_pixel *restrict thiserr = NULL; f_pixel *restrict nexterr = NULL; float sr=0, sg=0, sb=0, sa=0; int fs_direction = 1; /* Initialize Floyd-Steinberg error vectors. */ thiserr = malloc((cols + 2) * sizeof(*thiserr)); nexterr = malloc((cols + 2) * sizeof(*thiserr)); srandom(12345); /** deterministic dithering is better for comparing results */ for (int col = 0; col < cols + 2; ++col) { const double rand_max = RAND_MAX; thiserr[col].r = ((double)random() - rand_max/2.0)/rand_max/255.0; thiserr[col].g = ((double)random() - rand_max/2.0)/rand_max/255.0; thiserr[col].b = ((double)random() - rand_max/2.0)/rand_max/255.0; thiserr[col].a = ((double)random() - rand_max/2.0)/rand_max/255.0; } for (int row = 0; row < rows; ++row) { memset(nexterr, 0, (cols + 2) * sizeof(*nexterr)); int col = (fs_direction) ? 0 : (cols - 1); do { f_pixel px = to_f(gamma, input_pixels[row][col]); /* Use Floyd-Steinberg errors to adjust actual color. */ sr = px.r + thiserr[col + 1].r; sg = px.g + thiserr[col + 1].g; sb = px.b + thiserr[col + 1].b; sa = px.a + thiserr[col + 1].a; if (sr < 0) sr = 0; else if (sr > 1) sr = 1; if (sg < 0) sg = 0; else if (sg > 1) sg = 1; if (sb < 0) sb = 0; else if (sb > 1) sb = 1; if (sa < 0) sa = 0; /* when fighting IE bug, dithering must not make opaque areas transparent */ else if (sa > 1 || (ie_bug && px.a > 255.0/256.0)) sa = 1; if (sa < 1.0/256.0) { ind = transparent_ind; } else { float diff; ind = best_color_index((f_pixel){.r=sr, .g=sg, .b=sb, .a=sa}, map, min_opaque_val, &diff); remapped_pixels++; remapping_error += diff; } row_pointers[row][col] = ind; float colorimp = (3.0f + acolormap[ind].acolor.a)/4.0f; f_pixel xp = acolormap[ind].acolor; f_pixel err = { .r = (sr - xp.r) * colorimp, .g = (sg - xp.g) * colorimp, .b = (sb - xp.b) * colorimp, .a = (sa - xp.a), }; /* Propagate Floyd-Steinberg error terms. */ if (fs_direction) { thiserr[col + 2].a += (err.a * 7.0f) / 16.0f; thiserr[col + 2].r += (err.r * 7.0f) / 16.0f; thiserr[col + 2].g += (err.g * 7.0f) / 16.0f; thiserr[col + 2].b += (err.b * 7.0f) / 16.0f; nexterr[col ].a += (err.a * 3.0f) / 16.0f; nexterr[col ].r += (err.r * 3.0f) / 16.0f; nexterr[col ].g += (err.g * 3.0f) / 16.0f; nexterr[col ].b += (err.b * 3.0f) / 16.0f; nexterr[col + 1].a += (err.a * 5.0f) / 16.0f; nexterr[col + 1].r += (err.r * 5.0f) / 16.0f; nexterr[col + 1].g += (err.g * 5.0f) / 16.0f; nexterr[col + 1].b += (err.b * 5.0f) / 16.0f; nexterr[col + 2].a += (err.a ) / 16.0f; nexterr[col + 2].r += (err.r ) / 16.0f; nexterr[col + 2].g += (err.g ) / 16.0f; nexterr[col + 2].b += (err.b ) / 16.0f; } else { thiserr[col ].a += (err.a * 7.0f) / 16.0f; thiserr[col ].r += (err.r * 7.0f) / 16.0f; thiserr[col ].g += (err.g * 7.0f) / 16.0f; thiserr[col ].b += (err.b * 7.0f) / 16.0f; nexterr[col ].a += (err.a ) / 16.0f; nexterr[col ].r += (err.r ) / 16.0f; nexterr[col ].g += (err.g ) / 16.0f; nexterr[col ].b += (err.b ) / 16.0f; nexterr[col + 1].a += (err.a * 5.0f) / 16.0f; nexterr[col + 1].r += (err.r * 5.0f) / 16.0f; nexterr[col + 1].g += (err.g * 5.0f) / 16.0f; nexterr[col + 1].b += (err.b * 5.0f) / 16.0f; nexterr[col + 2].a += (err.a * 3.0f) / 16.0f; nexterr[col + 2].r += (err.r * 3.0f) / 16.0f; nexterr[col + 2].g += (err.g * 3.0f) / 16.0f; nexterr[col + 2].b += (err.b * 3.0f) / 16.0f; } if (fs_direction) { ++col; if (col >= cols) break; } else { --col; if (col < 0) break; } } while(1); f_pixel *temperr; temperr = thiserr; thiserr = nexterr; nexterr = temperr; fs_direction = !fs_direction; } return remapping_error / MAX(1, remapped_pixels); }