static int test_save_PNG(GP_PixelType pixel_type) { GP_Context *ctx; int ret; ctx = GP_ContextAlloc(100, 100, pixel_type); if (ctx == NULL) { tst_msg("Failed to allocate context"); return TST_UNTESTED; } errno = 0; ret = GP_SavePNG(ctx, "/dev/null", NULL); if (ret == 0) { tst_msg("Saved successfully"); GP_ContextFree(ctx); return TST_SUCCESS; } switch (errno) { case ENOSYS: tst_msg("Not Implemented"); GP_ContextFree(ctx); return TST_SKIPPED; default: tst_msg("Failed and errno is not ENOSYS (%i)", errno); GP_ContextFree(ctx); return TST_FAILED; } }
static int test_load_PNG(const char *path) { GP_Context *img; errno = 0; img = GP_LoadPNG(path, NULL); if (img == NULL) { switch (errno) { case ENOSYS: tst_msg("Not Implemented"); return TST_SKIPPED; default: tst_msg("Got %s", strerror(errno)); return TST_FAILED; } } /* * TODO: check correct data. */ GP_ContextFree(img); return TST_SUCCESS; }
int main(int argc, char *argv[]) { GP_Context *img; struct callback_priv priv; GP_ProgressCallback callback = {.callback = progress_callback, .priv = &priv}; if (argc != 2) { fprintf(stderr, "Takes an image as an parameter\n"); return 1; } priv.op = "Loading"; priv.name = argv[1]; img = GP_LoadImage(argv[1], &callback); if (img == NULL) { fprintf(stderr, "Failed to load image '%s':%s\n", argv[1], strerror(errno)); return 1; } printf("\n"); priv.op = "Saving"; priv.name = "tmp.gfx"; if (GP_SaveTmpFile(img, priv.name, &callback)) { fprintf(stderr, "Failed to save temp file %s\n", strerror(errno)); return 1; } printf("\n"); GP_ContextFree(img); priv.op = "Loading"; img = GP_LoadTmpFile(priv.name, &callback); if (img == NULL) { fprintf(stderr, "Failed to load temp file %s\n", strerror(errno)); return 1; } priv.op = "Saving"; priv.name = "out.png"; printf("\n"); if (GP_SavePNG(img, "out.png", &callback)) { fprintf(stderr, "Failed to save image %s\n", strerror(errno)); return 1; } printf("\n"); return 0; }
static int save_load(enum fmt fmt, GP_Size w, GP_Size h) { GP_Context *img, *res; img = GP_ContextAlloc(w, h, GP_PIXEL_RGB888); if (img == NULL) { tst_warn("GP_ContextAlloc failed"); return TST_UNTESTED; } int ret = save_img(fmt, img, "test"); if (ret) { if (errno == ENOSYS) { tst_msg("Save %s: ENOSYS", strfmt(fmt)); return TST_SKIPPED; } tst_msg("Failed to save %s: %s", strfmt(fmt), strerror(errno)); return TST_FAILED; } res = load(fmt, "test"); if (res == NULL) { tst_msg("Failed to load %s: %s", strfmt(fmt), strerror(errno)); return TST_FAILED; } GP_ContextFree(img); GP_ContextFree(res); return TST_SUCCESS; }
static int test_load_PNG_check_color(struct check_color_test *test) { GP_Context *img; errno = 0; img = GP_LoadPNG(test->path, NULL); if (img == NULL) { switch (errno) { case ENOSYS: tst_msg("Not Implemented"); return TST_SKIPPED; default: tst_msg("Got %s", strerror(errno)); return TST_FAILED; } } unsigned int x, y, fail = 0; for (x = 0; x < img->w; x++) { for (y = 0; y < img->w; y++) { GP_Pixel p = GP_GetPixel(img, x, y); if (p != test->pixel) { if (!fail) tst_msg("First failed at %u,%u %x %x", x, y, p, test->pixel); fail = 1; } } } if (!fail) tst_msg("Context pixels are correct"); GP_ContextFree(img); if (fail) return TST_FAILED; return TST_SUCCESS; }
GP_Context *GP_FilterGaussianBlurExAlloc(const GP_Context *src, GP_Coord x_src, GP_Coord y_src, GP_Size w_src, GP_Size h_src, float sigma_x, float sigma_y, GP_ProgressCallback *callback) { GP_Context *dst = GP_ContextAlloc(w_src, h_src, src->pixel_type); if (dst == NULL) return NULL; if (GP_FilterGaussianBlur_Raw(src, x_src, y_src, w_src, h_src, dst, 0, 0, sigma_x, sigma_y, callback)) { GP_ContextFree(dst); return NULL; } return dst; }
/* * Apply sobel operator. */ static int sobel(const GP_Context *src, GP_Context *dx, GP_Context *dy, GP_ProgressCallback *callback) { float dx_kern[] = { -1, 0, 1, -2, 0, 2, -1, 0, 1, }; GP_ConvolutionParams dx_conv = { .src = src, .x_src = 0, .y_src = 0, .w_src = src->w, .h_src = src->h, .dst = dx, .x_dst = 0, .y_dst = 0, .kernel = dx_kern, .kw = 3, .kh = 3, .kern_div = 1, .callback = callback, }; if (GP_FilterConvolution_Raw(&dx_conv)) return 1; float dy_kern[] = { -1, -2, -1, 0, 0, 0, 1, 2, 1, }; GP_ConvolutionParams dy_conv = { .src = src, .x_src = 0, .y_src = 0, .w_src = src->w, .h_src = src->h, .dst = dy, .x_dst = 0, .y_dst = 0, .kernel = dy_kern, .kw = 3, .kh = 3, .kern_div = 1, .callback = callback, }; if (GP_FilterConvolution_Raw(&dy_conv)) return 1; return 0; } static int edge_detect(const GP_Context *src, GP_Context **E, GP_Context **Phi, int type, GP_ProgressCallback *callback) { //TODO GP_ASSERT(src->pixel_type == GP_PIXEL_RGB888); GP_Context *dx, *dy; dx = GP_ContextCopy(src, 0); dy = GP_ContextCopy(src, 0); if (dx == NULL || dy == NULL) goto err0; switch (type) { case 0: if (sobel(src, dx, dy, callback)) goto err0; break; case 1: if (prewitt(src, dx, dy, callback)) goto err0; break; default: goto err0; } uint32_t i, j; for (i = 0; i < src->w; i++) { for (j = 0; j < src->h; j++) { GP_Pixel pix_x = GP_GetPixel_Raw_24BPP(dx, i, j); GP_Pixel pix_y = GP_GetPixel_Raw_24BPP(dy, i, j); int Rx, Gx, Bx; int Ry, Gy, By; int RE, GE, BE; int RPhi, GPhi, BPhi; Rx = GP_Pixel_GET_R_RGB888(pix_x); Gx = GP_Pixel_GET_G_RGB888(pix_x); Bx = GP_Pixel_GET_B_RGB888(pix_x); Ry = GP_Pixel_GET_R_RGB888(pix_y); Gy = GP_Pixel_GET_G_RGB888(pix_y); By = GP_Pixel_GET_B_RGB888(pix_y); RE = sqrt(Rx*Rx + Ry*Ry) + 0.5; GE = sqrt(Gx*Gx + Gy*Gy) + 0.5; BE = sqrt(Bx*Bx + By*By) + 0.5; GP_PutPixel_Raw_24BPP(dx, i, j, GP_Pixel_CREATE_RGB888(RE, GE, BE)); if (Rx != 0 && Ry != 0) RPhi = ((atan2(Rx, Ry) + M_PI) * 255)/(2*M_PI); else RPhi = 0; if (Gx != 0 && Gy != 0) GPhi = ((atan2(Gx, Gy) + M_PI) * 255)/(2*M_PI); else GPhi = 0; if (Bx != 0 && By != 0) BPhi = ((atan2(Bx, By) + M_PI) * 255)/(2*M_PI); else BPhi = 0; GP_PutPixel_Raw_24BPP(dy, i, j, GP_Pixel_CREATE_RGB888(RPhi, GPhi, BPhi)); } } if (Phi != NULL) *Phi = dy; else GP_ContextFree(dy); if (E != NULL) *E = dx; else GP_ContextFree(dx); return 0; err0: GP_ContextFree(dx); GP_ContextFree(dy); return 1; } int GP_FilterEdgeSobel(const GP_Context *src, GP_Context **E, GP_Context **Phi, GP_ProgressCallback *callback) { GP_DEBUG(1, "Sobel edge detection image %ux%u", src->w, src->h); return edge_detect(src, E, Phi, 0, callback); }
int GP_ReadJPGEx(GP_IO *io, GP_Context **img, GP_DataStorage *storage, GP_ProgressCallback *callback) { struct jpeg_decompress_struct cinfo; struct my_source_mgr src; struct my_jpg_err my_err; GP_Context *ret = NULL; uint8_t buf[1024]; int err; cinfo.err = jpeg_std_error(&my_err.error_mgr); my_err.error_mgr.error_exit = my_error_exit; if (setjmp(my_err.setjmp_buf)) { err = EIO; goto err2; } jpeg_create_decompress(&cinfo); init_source_mgr(&src, io, buf, sizeof(buf)); cinfo.src = (void*)&src; if (storage) save_jpg_markers(&cinfo); jpeg_read_header(&cinfo, TRUE); GP_DEBUG(1, "Have %s JPEG size %ux%u %i channels", get_colorspace(cinfo.jpeg_color_space), cinfo.image_width, cinfo.image_height, cinfo.num_components); //TODO: Propagate failure? if (storage) read_jpg_metadata(&cinfo, storage); if (!img) goto exit; GP_Pixel pixel_type; switch (cinfo.out_color_space) { case JCS_GRAYSCALE: pixel_type = GP_PIXEL_G8; break; case JCS_RGB: pixel_type = GP_PIXEL_BGR888; break; case JCS_CMYK: pixel_type = GP_PIXEL_CMYK8888; break; default: pixel_type = GP_PIXEL_UNKNOWN; } if (pixel_type == GP_PIXEL_UNKNOWN) { GP_DEBUG(1, "Can't handle %s JPEG output format", get_colorspace(cinfo.out_color_space)); err = ENOSYS; goto err1; } ret = GP_ContextAlloc(cinfo.image_width, cinfo.image_height, pixel_type); if (ret == NULL) { GP_DEBUG(1, "Malloc failed :("); err = ENOMEM; goto err1; } jpeg_start_decompress(&cinfo); switch (pixel_type) { case GP_PIXEL_BGR888: case GP_PIXEL_G8: err = load(&cinfo, ret, callback); break; case GP_PIXEL_CMYK8888: err = load_cmyk(&cinfo, ret, callback); break; default: err = EINVAL; } if (err) goto err2; jpeg_finish_decompress(&cinfo); exit: jpeg_destroy_decompress(&cinfo); GP_ProgressCallbackDone(callback); if (img) *img = ret; return 0; err2: GP_ContextFree(ret); err1: jpeg_destroy_decompress(&cinfo); errno = err; return 1; }
int GP_ReadGIFEx(GP_IO *io, GP_Context **img, GP_DataStorage *storage, GP_ProgressCallback *callback) { GifFileType *gf; GifRecordType rec_type; GP_Context *res = NULL; GP_Pixel bg; int32_t x, y; int err; errno = 0; #if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5 gf = DGifOpen(io, gif_input_func, NULL); #else gf = DGifOpen(io, gif_input_func); #endif if (gf == NULL) { /* * The giflib uses open() so when we got a failure and errno * is set => open() has failed. * * When errno is not set the file content was not valid so we * set errno to EIO. */ if (errno == 0) errno = EIO; return 1; } GP_DEBUG(1, "Have GIF image %ix%i, %i colors, %i bpp", gf->SWidth, gf->SHeight, gf->SColorResolution, gf->SColorMap ? gf->SColorMap->BitsPerPixel : -1); do { if (DGifGetRecordType(gf, &rec_type) != GIF_OK) { //TODO: error handling GP_DEBUG(1, "DGifGetRecordType() error %s (%i)", gif_err_name(gif_err(gf)), gif_err(gf)); err = EIO; goto err1; } GP_DEBUG(2, "Have GIF record type %s", rec_type_name(rec_type)); switch (rec_type) { case EXTENSION_RECORD_TYPE: if ((err = read_extensions(gf))) goto err1; continue; case IMAGE_DESC_RECORD_TYPE: break; default: continue; } if (DGifGetImageDesc(gf) != GIF_OK) { //TODO: error handling GP_DEBUG(1, "DGifGetImageDesc() error %s (%i)", gif_err_name(gif_err(gf)), gif_err(gf)); err = EIO; goto err1; } if (storage) fill_metadata(gf, storage); GP_DEBUG(1, "Have GIF Image left-top %ix%i, width-height %ix%i," " interlace %i, bpp %i", gf->Image.Left, gf->Image.Top, gf->Image.Width, gf->Image.Height, gf->Image.Interlace, gf->Image.ColorMap ? gf->Image.ColorMap->BitsPerPixel : -1); if (!img) break; res = GP_ContextAlloc(gf->SWidth, gf->SHeight, GP_PIXEL_RGB888); if (res == NULL) { err = ENOMEM; goto err1; } /* If background color is defined, use it */ if (get_bg_color(gf, &bg)) { GP_DEBUG(1, "Filling bg color %x", bg); GP_Fill(res, bg); } /* Now finally read gif image data */ for (y = gf->Image.Top; y < gf->Image.Height; y++) { uint8_t line[gf->Image.Width]; DGifGetLine(gf, line, gf->Image.Width); unsigned int real_y = y; if (gf->Image.Interlace == 64) { real_y = interlace_real_y(gf, y); GP_DEBUG(3, "Interlace y -> real_y %u %u", y, real_y); } //TODO: just now we have only 8BPP for (x = 0; x < gf->Image.Width; x++) GP_PutPixel_Raw_24BPP(res, x + gf->Image.Left, real_y, get_color(gf, line[x])); if (GP_ProgressCallbackReport(callback, y - gf->Image.Top, gf->Image.Height, gf->Image.Width)) { GP_DEBUG(1, "Operation aborted"); err = ECANCELED; goto err2; } } //TODO: now we exit after reading first image break; } while (rec_type != TERMINATE_RECORD_TYPE); DGifCloseFile(gf); /* No Image record found :( */ if (img && !res) { errno = EINVAL; return 1; } if (img) *img = res; return 0; err2: GP_ContextFree(res); err1: DGifCloseFile(gf); errno = err; return 1; }