int simpl_gray_copy(SimplGrayImage **dest_img, const SimplGrayImage *src_img) { int result; if (src_img && src_img->image && src_img->width && src_img->height) { if (*dest_img==src_img) return SIMPL_OK; result = simpl_gray(dest_img, src_img->width, src_img->height); if (result!=SIMPL_OK) return result; memcpy((*dest_img)->image, src_img->image, src_img->width * src_img->height * sizeof(SimplPixel)); } else return SIMPL_BAD_PARAMS; return SIMPL_OK; }
int simpl_gray_load_png(SimplGrayImage **image, SimplInStream istream, const SimplColorToGrayMethods method, const SimplPixel bk_value) { png_structp png_ptr; png_infop info_ptr; png_byte color_type, bitdepth, *row_data=NULL; png_bytep* row_ptrs=NULL; png_uint_32 i, j, x, width, height, row_size; SimplColorPixel *pixels=NULL; SimplPixel *iptr, *alpha=NULL; int value, out = SIMPL_INTERNAL; /* Create a read struct. */ if (!(png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) { return SIMPL_INTERNAL; } /* Create an info struct. */ if (!(info_ptr = png_create_info_struct(png_ptr))) { goto error; } /* Handle libpng errors with a magic setjmp. */ if (setjmp(png_jmpbuf(png_ptr))) { goto error; } /* Set the stream-based data source. */ png_set_read_fn(png_ptr, istream, StreamReadData); /* Read the info chunk. */ png_read_info(png_ptr, info_ptr); /* Get the dimensions and color information. */ width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); bitdepth = png_get_bit_depth(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); /* If palette, low bit depth gray, transparent w/o alpha, or 16 bit, fix it. */ if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); color_type = png_get_color_type(png_ptr, info_ptr); } else if (color_type == PNG_COLOR_TYPE_GRAY) { if (bitdepth<8) png_set_expand_gray_1_2_4_to_8(png_ptr); bitdepth = 8; } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); color_type = png_get_color_type(png_ptr, info_ptr); } png_set_strip_16(png_ptr); /* Either allocate a row, or load the entire image into a buffer. This is * because single row access uses less memory but doesn't work for * interlaced PNGs. */ row_size = png_get_rowbytes(png_ptr, info_ptr); if (png_get_interlace_type(png_ptr, info_ptr)==PNG_INTERLACE_NONE) { row_data = (png_byte *)malloc(sizeof(png_byte) * row_size); if (!row_data) { out = SIMPL_NOMEM; goto error; } } else { row_ptrs = (png_bytep*)calloc(height, sizeof(png_bytep)); if (!row_ptrs) { out = SIMPL_NOMEM; goto error; } for (j=0; j<height; ++j) { row_ptrs[j] = (png_byte *)malloc(sizeof(png_byte) * row_size); if (!row_ptrs[j]) { out = SIMPL_NOMEM; goto error; } } png_read_image(png_ptr, row_ptrs); } /* Allocate an image of the specified size. */ out = simpl_gray(image, width, height); if (out != SIMPL_OK) goto error; /* Decode the image line by line. */ if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) { pixels = (SimplColorPixel *)malloc(sizeof(SimplColorPixel) * width); if (!pixels) { out = SIMPL_NOMEM; goto error; } alpha = (SimplPixel *)malloc(sizeof(SimplPixel) * width); if (!alpha) { out = SIMPL_NOMEM; goto error; } memset(alpha, 255, width); for (j=0; j<height; j++) { if (row_ptrs) row_data = row_ptrs[j]; else png_read_row(png_ptr, row_data, NULL); iptr = (*image)->image + j * width; if (color_type==PNG_COLOR_TYPE_RGB) { for (x=i=0; x<width; ++x, i+=3) { pixels[x].red = row_data[i]; pixels[x].green = row_data[i+1]; pixels[x].blue = row_data[i+2]; } } else { for (x=i=0; x<width; ++x, i+=4) { pixels[x].red = row_data[i]; pixels[x].green = row_data[i+1]; pixels[x].blue = row_data[i+2]; alpha[x] = row_data[i+3]; } } switch(method) { case COLOR_TO_GRAY_RED: for (i=0; i<width; ++i) iptr[i] = pixels[i].red; break; case COLOR_TO_GRAY_GREEN: for (i=0; i<width; ++i) iptr[i] = pixels[i].green; break; case COLOR_TO_GRAY_BLUE: for (i=0; i<width; ++i) iptr[i] = pixels[i].blue; break; case COLOR_TO_GRAY_ALPHA: for (i=0; i<width; ++i) iptr[i] = alpha[i]; break; case COLOR_TO_GRAY_CIE: if (color_type==PNG_COLOR_TYPE_RGB_ALPHA) { for (i=0; i<width; ++i) { value = (6969*pixels[i].red + 23434*pixels[i].green + 2365*pixels[i].blue)>>15; value = (alpha[i]*value + (255-alpha[i])*bk_value) / 255; iptr[i] = (value>255)?255:value; } } else { for (i=0; i<width; ++i) { value = (6969*pixels[i].red + 23434*pixels[i].green + 2365*pixels[i].blue)>>15; iptr[i] = (value>255)?255:value; } } break; case COLOR_TO_GRAY_MEAN: default: if (color_type==PNG_COLOR_TYPE_RGB_ALPHA) { for (i=0; i<width; ++i) { value = (pixels[i].red + pixels[i].green + pixels[i].blue)/3; value = (alpha[i]*value + (255-alpha[i])*bk_value) / 255; iptr[i] = (value>255)?255:value; } } else { for (i=0; i<width; ++i) { value = (pixels[i].red + pixels[i].green + pixels[i].blue)/3; iptr[i] = (value>255)?255:value; } } break; } }
int simpl_gray_load_jpg(SimplGrayImage **image, SimplInStream istream, const SimplColorToGrayMethods method, const SimplPixel bk_value) { struct jpeg_decompress_struct cinfo; LibJpegErrorMgr jerr; JDIMENSION width, height, row_stride, i; JOCTET *row_data = NULL; int y, u, v; SimplColorPixel *row=NULL, *row_ptr; SimplPixel *ptr; int out = SIMPL_INTERNAL; /* Allocate and initialize JPEG decompression object. */ cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = JpegLoadErrorExit; /* Establish the setjmp return context for JpegLoadErrorExit to use. */ if (setjmp(jerr.setjmp_buffer)) { goto error; } /* Now we can initialize the JPEG decompression object and file. */ jpeg_create_decompress(&cinfo); JpegMyReader(&cinfo, istream); /* Read file parameters with jpeg_read_header(). */ jpeg_read_header(&cinfo, TRUE); /* Start decompresser. */ jpeg_start_decompress(&cinfo); /* Allocate the image and line buffer. */ width = cinfo.image_width; height = cinfo.image_height; row_stride = cinfo.output_width * cinfo.output_components; row_data = (JOCTET *)malloc(cinfo.image_width*4*sizeof(JOCTET)); if (!row_data) { out = SIMPL_NOMEM; goto error; } row = (SimplColorPixel *)malloc(width * sizeof(SimplColorPixel)); if (!row) { out = SIMPL_NOMEM; goto error; } out = simpl_gray(image, width, height); if (out != SIMPL_OK) goto error; ptr = (*image)->image; /* Extract the image. */ if (cinfo.out_color_space==JCS_GRAYSCALE) { while (cinfo.output_scanline < cinfo.output_height) { jpeg_read_scanlines(&cinfo, &row_data, 1); for (i=0; i<row_stride; i++) ptr[i] = row_data[i]; ptr += width; } } else if (cinfo.out_color_space==JCS_RGB || cinfo.out_color_space==JCS_YCbCr || cinfo.out_color_space==JCS_CMYK) { while (cinfo.output_scanline < cinfo.output_height) { jpeg_read_scanlines(&cinfo, &row_data, 1); row_ptr = row; if (cinfo.out_color_space==JCS_RGB) { for (i=0; i<row_stride; i+=3) { row_ptr->red = row_data[i]; row_ptr->green = row_data[i+1]; row_ptr->blue = row_data[i+2]; ++row_ptr; } } else if (cinfo.out_color_space==JCS_YCbCr) { for (i=0; i<row_stride; i+=3) { y = row_data[i]; u = row_data[i+1]; v = row_data[i+2]; row_ptr->red = y + ((360*(v-128))>>8); row_ptr->green = y - ((88*(u-128)+183*(v-128))>>8); row_ptr->blue = y + ((455 * (u-128))>>8); ++row_ptr; } } else { for (i=0; i<row_stride; i+=4) { y = 255 - row_data[i+3]; row_ptr->red = y - ((row_data[i]*y)>>8); row_ptr->green = y - ((row_data[i+1]*y)>>8); row_ptr->blue = y - ((row_data[i+2]*y)>>8); ++row_ptr; } } switch(method) { case COLOR_TO_GRAY_RED: for (i=0; i<width; ++i) ptr[i] = row[i].red; break; case COLOR_TO_GRAY_GREEN: for (i=0; i<width; ++i) ptr[i] = row[i].green; break; case COLOR_TO_GRAY_BLUE: for (i=0; i<width; ++i) ptr[i] = row[i].blue; break; case COLOR_TO_GRAY_ALPHA: for (i=0; i<width; ++i) ptr[i] = 255; break; case COLOR_TO_GRAY_CIE: for (i=0; i<width; ++i) { y = (6969*row[i].red + 23434*row[i].green + 2365*row[i].blue)>>15; ptr[i] = (y>255)?255:y; } break; case COLOR_TO_GRAY_MEAN: default: for (i=0; i<width; ++i) { y = (row[i].red + row[i].green + row[i].blue)/3; ptr[i] = (y>255)?255:y; } break; } ptr += width; } } else {
int simpl_image_to_gray(SimplGrayImage **gray_img, const SimplImage *image, const SimplColorToGrayMethods method, const SimplPixel bk_value) { size_t i, size; int result, value; SimplPixel *out; if (image && image->image && image->width && image->height) { result = simpl_gray(gray_img, image->width, image->height); if (result!=SIMPL_OK) return result; size = image->width * image->height; out = (*gray_img)->image; switch (method) { case COLOR_TO_GRAY_RED: for (i=0; i<size; ++i) { out[i] = image->image[i].red; } break; case COLOR_TO_GRAY_GREEN: for (i=0; i<size; ++i) { out[i] = image->image[i].green; } break; case COLOR_TO_GRAY_BLUE: for (i=0; i<size; ++i) { out[i] = image->image[i].blue; } break; case COLOR_TO_GRAY_ALPHA: if (image->alpha) { for (i=0; i<size; ++i) { out[i] = image->alpha[i]; } } else { for (i=0; i<size; ++i) { out[i] = 255; } } break; case COLOR_TO_GRAY_CIE: if (image->alpha) { for (i=0; i<size; ++i) { value = (6969*image->image[i].red + 23434*image->image[i].green + 2365*image->image[i].blue)>>15; value = (image->alpha[i]*value + (255-image->alpha[i])*bk_value) / 255; out[i] = (value>255)?255:value; } } else { for (i=0; i<size; ++i) { value = (6969*image->image[i].red + 23434*image->image[i].green + 2365*image->image[i].blue)>>15; out[i] = (value>255)?255:value; } } break; case COLOR_TO_GRAY_MEAN: default: if (image->alpha) { for (i=0; i<size; ++i) { value = (image->image[i].red + image->image[i].green + image->image[i].blue) / 3; value = (image->alpha[i]*value + (255-image->alpha[i])*bk_value) / 255; out[i] = (value>255)?255:value; } } else { for (i=0; i<size; ++i) { value = (image->image[i].red + image->image[i].green + image->image[i].blue) / 3; out[i] = (value>255)?255:value; } } break; }