//-------------------------------------------------------------------------- static unsigned int HSLtoRGB( bool bRealRgb, unsigned int H, unsigned int S, unsigned int L) { if (S == 0) { // achromatic return make_rgb(bRealRgb, L, L, L); } double h = (double)H*360/255; double s = (double)S / 255; double l = (double)L / 255; double rm1, rm2; if (l <= 0.5) rm2 = l + l * s; else rm2 = l + s - l * s; rm1 = 2.0 * l - rm2; return make_rgb(bRealRgb, to_rgb(rm1, rm2, h + 120.0), to_rgb(rm1, rm2, h), to_rgb(rm1, rm2, h - 120.0) ); }
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; } }
#include "work.h" #include <stdio.h> void get_time(imagedata_t *img, const char *fn, logger_t *l) { /*{{{*/ // this is a hack that is targeted to a // specific small set of jpeg images, // not expected, or more so, expected to // not work with arbitrary files log(l, "trying to open \"%s\"\n", fn); FILE *fd = fopen(fn, "rb"); assert(fd); char dstr[20]; fseek(fd, 188, SEEK_SET); fread(dstr, sizeof(char), 19, fd); fclose(fd); dstr[19] = '\0'; // 2013:12:27 18:20:32 // 0123456789012345678 img->time.tm_year = atoi(dstr)-1900; img->time.tm_mon = atoi(dstr+5); img->time.tm_mday = atoi(dstr+8); img->time.tm_hour = atoi(dstr+11); img->time.tm_min = atoi(dstr+14); img->time.tm_sec = atoi(dstr+17); img->stamp = mktime(&img->time); log(l, "%s -> %s -> %04d-%02d-%02d %02d:%02d:%02d -> %Ld\n", fn, dstr, img->time.tm_year, img->time.tm_mon, img->time.tm_mday, img->time.tm_hour, img->time.tm_min, img->time.tm_sec, img->stamp ); } /*}}}*/ void scalepow2(bitmap_t *out, bitmap_t *in, unsigned int spow) { /*{{{*/ unsigned int limit = 1<<spow; for (size_t ty=0; ty<out->height; ++ty) { for (size_t tx=0; tx<out->width; ++tx) { size_t tp = tx + ty*out->width; unsigned int ys = 0; unsigned int cbs = 0; unsigned int crs = 0; size_t ctr = 0; for (size_t y=0; y<limit; ++y) { size_t sy = ty*limit + y; if (sy >= in->height) { break; } for (size_t x=0; x<limit; ++x) { size_t sx = tx*limit + x; if (sx >= in->width) { break; } size_t sp = sx + sy*in->width; ys += in->data[sp].x[0]; cbs += in->data[sp].x[1]; crs += in->data[sp].x[2]; ++ctr; } } ctr = ctr==0?1:ctr; out->data[tp].x[0] = ys/ctr; out->data[tp].x[1] = cbs/ctr; out->data[tp].x[2] = crs/ctr; } } } /*}}}*/ void init_threaddata(threaddata_t *td, const char *ofmt, const char *ifmt, int start, int stop) { /*{{{*/ log_init(&td->common.l, stdout); log(&td->common.l, "- logger created\n"); td->common.writerstr = calloc(strlen(ofmt)+32, sizeof(char)); assert(td->common.writerstr != NULL); sprintf(td->common.writerstr, "pnmtojpeg -quality=100 > %s", ofmt); log(&td->common.l, "- output shape is '%s'\n", td->common.writerstr); td->common.readerfmt = ifmt; td->common.readerstr = calloc(strlen(ifmt)+16, sizeof(char)); assert(td->common.readerstr != NULL); sprintf(td->common.readerstr, "jpegtopnm < %s", ifmt); log(&td->common.l, "- input shape is '%s'\n", td->common.readerstr); log(&td->common.l, "- initializing counter\n"); counter_init(&td->counter, start, stop); log(&td->common.l, "- initializing buffer\n"); buffer_init(&td->buffer, BUFFERSIZE, loader, unloader); //font_load_gz(&td->font, "data/sun12x22.psfu"); font_load_gz(&td->font, "/usr/share/kbd/consolefonts/sun12x22.psfu.gz"); } /*}}}*/ void destroy_threaddata(threaddata_t *td) { /*{{{*/ buffer_destroy(&td->buffer, &td->common); log(&td->common.l, "- destroying counter\n"); counter_destroy(&td->counter); log(&td->common.l, "- destroying logger\n"); log_destroy(&td->common.l); free(td->common.writerstr); free(td->common.readerstr); } /*}}}*/ void *loader(unsigned int index, void* old, void* state, int *status) { /*{{{*/ ioglobals_t *common = (ioglobals_t*) state; char *command = calloc(strlen(common->readerstr)+128, sizeof(char)); char *fn = calloc(strlen(common->readerfmt)+128, sizeof(char)); sprintf(command, common->readerstr, index); sprintf(fn, common->readerfmt, index); imagedata_t *imd = (imagedata_t*)old; if (imd == NULL) { imd = calloc(sizeof(imagedata_t), 1); } assert(imd != NULL); get_time(imd, fn, &common->l); log(&common->l, "reading file %u (%s) with command '%s'\n", index, fn, command); free(fn); FILE *pfd = popen(command, "r"); if (!pfd) { perror(NULL); } assert(pfd != NULL); int flag = PPM_OK; imd->orig = ppm_fread(imd->orig, pfd, &flag); pclose(pfd); free(command); assert(flag == PPM_OK); assert(imd->orig != NULL); log(&common->l, "wxh: %u x %u\n", imd->orig->width, imd->orig->height); unsigned int values[NSC] = {0, 3}; unsigned int powers[NSC] = {1, 8}; // index zero never used for (size_t i=0; i<NSC; ++i) { unsigned int additive = powers[i]-1; imd->tfsc[i] = bitmap_new(imd->tfsc[i], (imd->orig->width+additive)/powers[i], (imd->orig->height+additive)/powers[i]); assert(imd->tfsc[i] != NULL); log(&common->l, "index %u: created image %u/%u for colour transform and dimensions %u x %u\n", index, i, NSC, imd->tfsc[i]->width, imd->tfsc[i]->height); } to_ycbcr(imd->tfsc[0]->data, imd->orig->data, imd->orig->width*imd->orig->height); for (size_t i=1; i<NSC; ++i) { scalepow2(imd->tfsc[i], imd->tfsc[0], values[i]); } return imd; } /*}}}*/ void unloader(void *data, unsigned int index, void *state, bool kill) { /*{{{*/ ioglobals_t *common = (ioglobals_t*) state; if (!kill) { log(&common->l, "relinquishing index %u\n", index); } else { imagedata_t *imd = (imagedata_t*) data; bitmap_free(imd->orig); for (size_t i=0; i<NSC; ++i) { bitmap_free(imd->tfsc[i]); } free(data); } } /*}}}*/ void saver(unsigned int index, bitmap_t *data, ioglobals_t *common) { /*{{{*/ char *command = calloc(strlen(common->writerstr)+128, sizeof(char)); to_rgb(data->data, data->data, data->width*data->height); sprintf(command, common->writerstr, index); log(&common->l, "writing file %u with command '%s'\n", index, command); FILE *pfd = popen(command, "w"); if (!pfd) { perror(NULL); } assert(pfd); ppm_fwrite(pfd, data); pclose(pfd); free(command); } /*}}}*/
void magick_wrapper::xyuv_from_yuv_image_444(const xyuv::yuv_image &yuv_image_444, const xyuv::conversion_matrix &conversion_matrix) { // Resize underlying image to the input image. // Warning, this call has been slightly buggy for some resolutions. // It's better construct the image correctly in the first place. if (image.rows() != yuv_image_444.image_h || image.columns() != yuv_image_444.image_w ) { image.resize(Magick::Geometry(yuv_image_444.image_w, yuv_image_444.image_h)); } bool has_y = !yuv_image_444.y_plane.empty(); bool has_u = !yuv_image_444.u_plane.empty(); bool has_v = !yuv_image_444.v_plane.empty(); bool has_a = !yuv_image_444.a_plane.empty(); image.matte(has_a); // Create pixels with default values. // Note that this hides the lack of planes. rgb_color rgb; yuv_color yuv; Magick::PixelPacket *pixels = image.setPixels(0, 0, yuv_image_444.image_w, yuv_image_444.image_h); XYUV_ASSERT(pixels != nullptr); for (uint32_t y = 0; y < yuv_image_444.image_h; y++) { for (uint32_t x = 0; x < yuv_image_444.image_w; x++) { // Convert data. get_yuv_color(yuv, yuv_image_444, x, y); to_rgb(&rgb, yuv, conversion_matrix, has_y, has_u, has_v); // Wrap into ImageMagick ColorRGB Magick::ColorRGB magick_rgb; magick_rgb.red(rgb.r); magick_rgb.green(rgb.g); magick_rgb.blue(rgb.b); // Imagemagick stores alpha as 0.0 = opaque if (has_a) magick_rgb.alpha(1.0-rgb.a); // Assign pixel. pixels[y * image.columns() + x] = magick_rgb; } } // Commit changes to image. image.syncPixels(); }
void sort_palette(write_info *output_image, colormap *map) { assert(map); assert(output_image); /* ** Step 3.5 [GRR]: remap the palette colors so that all entries with ** the maximal alpha value (i.e., fully opaque) are at the end and can ** therefore be omitted from the tRNS chunk. */ verbose_printf(" eliminating opaque tRNS-chunk entries..."); /* move transparent colors to the beginning to shrink trns chunk */ int num_transparent=0; for(int i=0; i < map->colors; i++) { rgb_pixel px = to_rgb(output_image->gamma, map->palette[i].acolor); if (px.a != 255) { if (i != num_transparent) { colormap_item tmp = map->palette[num_transparent]; map->palette[num_transparent] = map->palette[i]; map->palette[i] = tmp; i--; } num_transparent++; } } verbose_printf("%d entr%s transparent\n", num_transparent, (num_transparent == 1)? "y" : "ies"); /* colors sorted by popularity make pngs slightly more compressible * opaque and transparent are sorted separately */ qsort(map->palette, num_transparent, sizeof(map->palette[0]), compare_popularity); qsort(map->palette+num_transparent, map->colors-num_transparent, sizeof(map->palette[0]), compare_popularity); output_image->num_palette = map->colors; output_image->num_trans = num_transparent; }
inline ColorSpace::Converter const &ColorSpace::to_rgb(WordType w, bool source_has_alpha, bool target_has_alpha) const { return to_rgb(w, get_alpha_type(source_has_alpha, target_has_alpha)); }