static RSFilterResponse * get_image(RSFilter *filter, const RSFilterRequest *request) { RSDcp *dcp = RS_DCP(filter); RSDcpClass *klass = RS_DCP_GET_CLASS(dcp); GdkRectangle *roi; RSFilterResponse *previous_response; RSFilterResponse *response; RS_IMAGE16 *input; RS_IMAGE16 *output; RS_IMAGE16 *tmp; gint j; RSFilterRequest *request_clone = rs_filter_request_clone(request); if (!dcp->use_profile) { gfloat premul[4] = {dcp->pre_mul.x, dcp->pre_mul.y, dcp->pre_mul.z, 1.0}; rs_filter_param_set_float4(RS_FILTER_PARAM(request_clone), "premul", premul); } rs_filter_param_set_object(RS_FILTER_PARAM(request_clone), "colorspace", klass->prophoto); previous_response = rs_filter_get_image(filter->previous, request_clone); g_object_unref(request_clone); if (!RS_IS_FILTER(filter->previous)) return previous_response; input = rs_filter_response_get_image(previous_response); if (!input) return previous_response; response = rs_filter_response_clone(previous_response); /* We always deliver in ProPhoto */ rs_filter_param_set_object(RS_FILTER_PARAM(response), "colorspace", klass->prophoto); g_object_unref(previous_response); if ((roi = rs_filter_request_get_roi(request))) { /* Align so we start at even pixel counts */ roi->width += (roi->x&1); roi->x -= (roi->x&1); roi->width = MIN(input->w - roi->x, roi->width); output = rs_image16_copy(input, FALSE); tmp = rs_image16_new_subframe(output, roi); bit_blt((char*)GET_PIXEL(tmp,0,0), tmp->rowstride * 2, (const char*)GET_PIXEL(input,roi->x,roi->y), input->rowstride * 2, tmp->w * tmp->pixelsize * 2, tmp->h); } else { output = rs_image16_copy(input, TRUE); tmp = g_object_ref(output); } g_object_unref(input); rs_filter_response_set_image(response, output); g_object_unref(output); g_static_rec_mutex_lock(&dcp_mutex); init_exposure(dcp); guint i, y_offset, y_per_thread, threaded_h; guint threads = rs_get_number_of_processor_cores(); if (tmp->h * tmp->w < 200*200) threads = 1; ThreadInfo *t = g_new(ThreadInfo, threads); threaded_h = tmp->h; y_per_thread = (threaded_h + threads-1)/threads; y_offset = 0; for (i = 0; i < threads; i++) { t[i].tmp = tmp; t[i].start_y = y_offset; t[i].start_x = 0; t[i].dcp = dcp; y_offset += y_per_thread; y_offset = MIN(tmp->h, y_offset); t[i].end_y = y_offset; for(j = 0; j < 256; j++) t[i].curve_input_values[j] = 0; t[i].single_thread = (threads == 1); if (threads == 1) start_single_dcp_thread(&t[0]); else t[i].threadid = g_thread_create(start_single_dcp_thread, &t[i], TRUE, NULL); } /* Wait for threads to finish */ for(i = 0; threads > 1 && i < threads; i++) g_thread_join(t[i].threadid); /* Settings can change now */ g_static_rec_mutex_unlock(&dcp_mutex); /* If we must deliver histogram data, do it now */ if (dcp->read_out_curve) { gint *values = g_malloc0(256*sizeof(gint)); for(i = 0; i < threads; i++) for(j = 0; j < 256; j++) values[j] += t[i].curve_input_values[j]; rs_curve_set_histogram_data(RS_CURVE_WIDGET(dcp->read_out_curve), values); g_free(values); } g_free(t); g_object_unref(tmp); return response; }
/** * Open an image using libpng * @param filename The filename to open * @return The newly created RS_IMAGE16 or NULL on error */ static RSFilterResponse* load_png(const gchar *filename) { gfloat gamma_guess = 2.2f; RSColorSpace *input_space = exiv2_get_colorspace(filename, &gamma_guess); int width, height, rowbytes; png_byte color_type; png_byte bit_depth; png_structp png_ptr; png_infop info_ptr; png_bytep * row_pointers; unsigned char header[8]; // 8 is the maximum size that can be checked /* open file and test for it being a png */ FILE *fp = fopen(filename, "rb"); if (!fp) return NULL; if (!fread(header, 1, 8, fp)) return NULL; if (png_sig_cmp(header, 0, 8)) return NULL; /* initialize stuff */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) return NULL; info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) return NULL; if (setjmp(png_jmpbuf(png_ptr))) return NULL; png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); #ifdef DEBUG printf("width: %u\n", (guint32) width); printf("height: %u\n", (guint32) height); printf("bit_depth: %d\n", bit_depth); printf("color_type: %d\n", color_type); #endif /* currently we only support 16BIT RGBA */ if (color_type != PNG_COLOR_TYPE_RGB_ALPHA || bit_depth != 16) return NULL; png_read_update_info(png_ptr, info_ptr); /* read file */ if (setjmp(png_jmpbuf(png_ptr))) return NULL; row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); if (bit_depth == 16) rowbytes = width*8; else rowbytes = width*4; gint y,x; gint dest = 0; for (y=0; y<height; y++) row_pointers[y] = (png_byte*) malloc(rowbytes); png_read_image(png_ptr, row_pointers); RS_IMAGE16 *image = rs_image16_new(width, height, 3, 4); for (y=0; y<height; y++) { png_byte* row = row_pointers[y]; for (x=0; x<width; x++) { png_byte* ptr = &(row[x*8]); image->pixels[dest++] = CLAMP((ptr[0]<<8)|ptr[1], 0, 65535); image->pixels[dest++] = CLAMP((ptr[2]<<8)|ptr[3], 0, 65535); image->pixels[dest++] = CLAMP((ptr[4]<<8)|ptr[5], 0, 65335); dest++; } } RSFilterResponse* response = rs_filter_response_new(); if (image) { rs_filter_response_set_image(response, image); rs_filter_response_set_width(response, image->w); rs_filter_response_set_height(response, image->h); g_object_unref(image); rs_filter_param_set_object(RS_FILTER_PARAM(response), "embedded-colorspace", input_space); rs_filter_param_set_boolean(RS_FILTER_PARAM(response), "is-premultiplied", TRUE); } return response; return NULL; }