/* --*- c -*-- * Copyright (C) 2016 Enrico Scholz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "testsuite/gen-image-cmdline.h" struct image_param { size_t width; size_t height; unsigned int bpp; enum { FMT_GBRG, FMT_BGGR, FMT_RGGB, FMT_GRBG } format; void * mem; size_t mem_sz; }; static void *write_pixel(void *out, unsigned int pix, unsigned int bpp) { switch ((bpp + 7) / 8) { case 1: { uint8_t v = pix; out = mempcpy(out, &v, sizeof v); break; } case 2: { uint16_t v = pix; out = mempcpy(out, &v, sizeof v); break; } case 4: { uint32_t v = pix; out = mempcpy(out, &v, sizeof v); break; } default: abort(); } return out; } static bool set_pixel(struct image_param const *image, unsigned int x, unsigned int y, unsigned int pix) { size_t offs; void *out; if (x >= image->width || y >= image->height) return false; offs = y * image->width + x; offs *= (image->bpp + 7)/8; out = image->mem + offs; write_pixel(out, pix, image->bpp); return true; } static void fill_bayer_rows(unsigned int row_mem[2][2], struct image_param const *image, unsigned int red, unsigned int green, unsigned int blue) { unsigned int row[2][2]; size_t bpp = image->bpp; switch (image->format) { case FMT_GBRG: row[0][0] = green; row[0][1] = blue; row[1][0] = red; row[1][1] = green; break; case FMT_BGGR: row[0][0] = blue; row[0][1] = green; row[1][0] = green; row[1][1] = red; break; case FMT_RGGB: row[0][0] = red; row[0][1] = green; row[1][0] = green; row[1][1] = blue; break; case FMT_GRBG: row[0][0] = green; row[0][1] = red; row[1][0] = blue; row[1][1] = green; break; } for (size_t x = 0; x < 2; ++x) { for (size_t y = 0; y < 2; ++y) write_pixel(&row_mem[y][x], row[y][x], bpp); } } static void gen_image_solid(struct image_param const *image, unsigned int red, unsigned int green, unsigned int blue) { unsigned int rows[2][2]; void *out = image->mem; size_t bpp = image->bpp; fill_bayer_rows(rows, image, red, green, blue); for (size_t y = 0; y < image->height; ++y) { unsigned int const *row = rows[y%2]; for (size_t x = 0; x < image->width; ++x) out = mempcpy(out, &row[x%2], (bpp+7)/8); } } static void gen_image_random(struct image_param const *image) { void *out = image->mem; size_t bpp = image->bpp; for (size_t y = 0; y < image->height; ++y) { for (size_t x = 0; x < image->width; ++x) out = write_pixel(out, random(), bpp); } } static void gen_image_seq(struct image_param const *image) { void *out = image->mem; size_t bpp = image->bpp; unsigned int cnt = 0; for (size_t y = 0; y < image->height; ++y) { for (size_t x = 0; x < image->width; ++x) { out = write_pixel(out, cnt, bpp); ++cnt; } } } static void gen_image_column(struct image_param const *image, unsigned int col, unsigned int red, unsigned int green, unsigned int blue) { unsigned int rows[2][2]; unsigned int bg[2] = { 0, 0 }; void *out = image->mem; size_t bpp = image->bpp; fill_bayer_rows(rows, image, red, green, blue); for (size_t y = 0; y < image->height; ++y) { unsigned int const *row = rows[y%2]; for (size_t x = 0; x < image->width; ++x) { unsigned int const *c = (x != col) ? &bg[x%2] : &row[x%2]; out = mempcpy(out, c, (bpp+7)/8); } } } /* Usage: gen-image [*] */ int main(int argc, char *argv[]) { struct gengetopt_args_info args; void *mem; size_t imgsize; struct image_param image; ssize_t l; if (cmdline_parser(argc, argv, &args) != 0) return EX_USAGE; if ((argc - optind) % 3) { fprintf(stderr, "bad modification args\n"); return EX_USAGE; } imgsize = args.width_arg * args.height_arg * ((args.bpp_arg + 7) / 8); mem = calloc(1, imgsize); image = (struct image_param) { .width = args.width_arg, .height = args.height_arg, .bpp = args.bpp_arg, .mem = mem, .mem_sz = imgsize, }; switch (args.format_arg) { case format_arg_gbrg: image.format = FMT_GBRG; break; case format_arg_bggr: image.format = FMT_BGGR; break; case format_arg_rggb: image.format = FMT_RGGB; break; case format_arg_grbg: image.format = FMT_GRBG; break; default: abort(); } if (args.grey_given) { if (!args.red_given) args.red_arg = args.grey_arg; if (!args.green_given) args.green_arg = args.grey_arg; if (!args.blue_given) args.blue_arg = args.grey_arg; } switch (args.method_arg) { case method_arg_solid: gen_image_solid(&image, args.red_arg, args.green_arg, args.blue_arg); break; case method_arg_random: if (args.seed_given) srandom(args.seed_arg); else srandom(time(NULL)); gen_image_random(&image); break; case method_arg_seq: gen_image_seq(&image); break; case method_arg_column: gen_image_column(&image, args.column_arg, args.red_arg, args.green_arg, args.blue_arg); break; default: abort(); } for (int i = optind; i < argc; i += 3) { unsigned int row = strtoul(argv[i+0], NULL, 0); unsigned int col = strtoul(argv[i+1], NULL, 0); unsigned int pix = strtoul(argv[i+2], NULL, 0); if (!set_pixel(&image, row, col, pix)) { fprintf(stderr, "bad pixel modification '%d %d %d'\n", row, col, pix); return EX_USAGE; } } l = write(STDOUT_FILENO, image.mem, image.mem_sz); if (l < 0) { perror("write()"); return EX_OSERR; } if ((size_t)l != image.mem_sz) { fprintf(stderr, "only partial image written\n"); return EX_OSERR; } return EX_OK; }