Add export format options: CSV, JSON, PPM
[gencolormap.git] / cmdline.cpp
index e49702f..4d8c753 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2015, 2016 Computer Graphics Group, University of Siegen
+ * Copyright (C) 2015, 2016, 2017, 2018, 2019
+ * Computer Graphics Group, University of Siegen
  * Written by Martin Lambers <martin.lambers@uni-siegen.de>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -32,6 +33,7 @@ extern char *optarg;
 extern int optind;
 
 #include "colormap.hpp"
+#include "export.hpp"
 
 enum type {
     brewer_seq,
@@ -49,12 +51,19 @@ enum type {
     mcnames
 };
 
+enum format {
+    csv,
+    json,
+    ppm
+};
+
 int main(int argc, char* argv[])
 {
     bool print_version = false;
     bool print_help = false;
-    int type = -1;
-    int n = -1;
+    int format = csv;
+    int type = brewer_seq;
+    int n = 256;
     float hue = -1.0f;
     float divergence = -1.0f;
     float contrast = -1.0f;
@@ -74,6 +83,7 @@ int main(int argc, char* argv[])
     struct option options[] = {
         { "version",     no_argument,       0, 'v' },
         { "help",        no_argument,       0, 'H' },
+        { "format",      required_argument, 0, 'f' },
         { "type",        required_argument, 0, 't' },
         { "n",           required_argument, 0, 'n' },
         { "hue",         required_argument, 0, 'h' },
@@ -94,7 +104,7 @@ int main(int argc, char* argv[])
     };
 
     for (;;) {
-        int c = getopt_long(argc, argv, "vHt:n:h:d:c:s:b:w:l:T:R:r:g:A:O:p:", options, NULL);
+        int c = getopt_long(argc, argv, "vHf:t:n:h:d:c:s:b:w:l:T:R:r:g:A:O:p:", options, NULL);
         if (c == -1)
             break;
         switch (c) {
@@ -104,6 +114,12 @@ int main(int argc, char* argv[])
         case 'H':
             print_help = true;
             break;
+        case 'f':
+            format = (strcmp(optarg, "csv") == 0 ? csv
+                    : strcmp(optarg, "json") == 0 ? json
+                    : strcmp(optarg, "ppm") == 0 ? ppm
+                    : -1);
+            break;
         case 't':
             type = (strcmp(optarg, "brewer-sequential") == 0 ? brewer_seq
                     : strcmp(optarg, "brewer-diverging") == 0 ? brewer_div
@@ -118,7 +134,7 @@ int main(int argc, char* argv[])
                     : strcmp(optarg, "cubehelix") == 0 ? cubehelix
                     : strcmp(optarg, "moreland") == 0 ? moreland
                     : strcmp(optarg, "mcnames") == 0 ? mcnames
-                    : -2);
+                    : -1);
             break;
         case 'n':
             n = atoi(optarg);
@@ -173,8 +189,9 @@ int main(int argc, char* argv[])
     }
 
     if (print_version) {
-        printf("gencolormap version 0.3\n"
-                "Copyright (C) 2016 Computer Graphics Group, University of Siegen.\n"
+        printf("gencolormap version 1.0\n"
+                "https://marlam.de/gencolormap\n"
+                "Copyright (C) 2019 Computer Graphics Group, University of Siegen.\n"
                 "Written by Martin Lambers <martin.lambers@uni-siegen.de>.\n"
                 "This is free software under the terms of the MIT/Expat License.\n"
                 "There is NO WARRANTY, to the extent permitted by law.\n");
@@ -182,58 +199,65 @@ int main(int argc, char* argv[])
     }
 
     if (print_help) {
-        printf("Usage: %s\n"
-                "  Common options, required for all types:\n"
-                "    -n|--n=N                         Set number of colors in the map\n"
-                "  Brewer-like color maps:\n"
-                "    -t|--type=brewer-sequential       Generate a sequential color map\n"
-                "    -t|--type=brewer-diverging        Generate a diverging color map\n"
-                "    -t|--type=brewer-qualitative      Generate a qualitative color map\n"
-                "    [-h|--hue=H]                      Set default hue in [0,360] degrees\n"
-                "    [-c|--contrast=C]                 Set contrast in [0,1]\n"
-                "    [-s|--saturation=S]               Set saturation in [0,1]\n"
-                "    [-b|--brightness=B]               Set brightness in [0,1]\n"
-                "    [-w|--warmth=W]                   Set warmth in [0,1] for seq. and div. maps\n"
-                "    [-d|--divergence=D]               Set divergence in deg. for div. and qual. maps\n"
-                "  Perceptually linear color maps:\n"
-                "    -t|--type=plsequential-lightness  Sequential map with varying lightness\n"
-                "    -t|--type=plsequential-saturation Sequential map with varying saturation\n"
-                "    -t|--type=plsequential-rainbow    Sequential map with varying hue (rainbow)\n"
-                "    -t|--type=plsequential-blackbody  Sequential map with varying hue (black body)\n"
-                "    -t|--type=pldiverging-lightness   Diverging map with varying lightness\n"
-                "    -t|--type=pldiverging-saturation  Diverging map with varying saturation\n"
-                "    -t|--type=plqualitative-hue       Qualitative map with evenly distributed hue\n"
-                "    [-l|--lightness=L]                Set lightness in [0,1]\n"
-                "    [-s|--saturation=S]               Set saturation in [0,1]\n"
-                "    [-h|--hue=H]                      Set default hue in [0,360] degrees\n"
-                "    [-d|--divergence=D]               Set divergence in deg. for div. and qual. maps\n"
-                "    [-r|--rotations=R]                Set number of rotations for rainbow maps\n"
-                "    [-T|--temperature=T]              Set start temp. in K for blackbody maps\n"
-                "    [-R|--range=R]                    Set temp. range in K for blackbody maps\n"
-                "  CubeHelix color maps:\n"
-                "    -t|--type=cubehelix               Generate a CubeHelix color map\n"
-                "    [-h|--hue=H]                      Set start hue in [0,180] degrees\n"
-                "    [-r|--rotations=R]                Set number of rotations, in (-infty,infty)\n"
-                "    [-s|--saturation=S]               Set saturation, in [0,1]\n"
-                "    [-g|--gamma=G]                    Set gamma correction, in (0,infty)\n"
-                "  Moreland diverging color maps:\n"
-                "    -t|--type=moreland                Generate a Moreland diverging color map\n"
-                "    [-A|--color0=sr,sg,sb             Set the first color as sRGB values in [0,255]\n"
-                "    [-O|--color1=sr,sg,sb             Set the last color as sRGB values in [0,255]\n"
-                "  McNames sequential color maps:\n"
-                "    -t|--type=mcnames                 Generate a McNames sequential color map\n"
-                "    [-p|--periods=P]                  Set the number of periods in (0, infty)\n"
-                "Generates a color map and prints it to standard output as sRGB triplets.\n"
-                "Report bugs to <martin.lambers@uni-siegen.de>.\n", argv[0]);
+        printf("Usage: %s [option...]\n"
+                "Generates a color map and prints it to standard output.\n"
+                "Prints the number of colors that had to be clipped to standard error.\n"
+                "Common options:\n"
+                "  [-f|--format=csv|json|ppm]          Set output format\n"
+                "  [-n|--n=N]                          Set number of colors in the map\n"
+                "Brewer-like color maps:\n"
+                "  [-t|--type=brewer-sequential]       Generate a sequential color map\n"
+                "  [-t|--type=brewer-diverging]        Generate a diverging color map\n"
+                "  [-t|--type=brewer-qualitative]      Generate a qualitative color map\n"
+                "  [-h|--hue=H]                        Set default hue in [0,360] degrees\n"
+                "  [-c|--contrast=C]                   Set contrast in [0,1]\n"
+                "  [-s|--saturation=S]                 Set saturation in [0,1]\n"
+                "  [-b|--brightness=B]                 Set brightness in [0,1]\n"
+                "  [-w|--warmth=W]                     Set warmth in [0,1] for seq. and div. maps\n"
+                "  [-d|--divergence=D]                 Set diverg. in deg for div. and qual. maps\n"
+                "Perceptually linear color maps:\n"
+                "  [-t|--type=plsequential-lightness]  Sequential map, varying lightness\n"
+                "  [-t|--type=plsequential-saturation] Sequential map, varying saturation\n"
+                "  [-t|--type=plsequential-rainbow]    Sequential map, varying hue (rainbow)\n"
+                "  [-t|--type=plsequential-blackbody]  Sequential map, varying hue (black body)\n"
+                "  [-t|--type=pldiverging-lightness]   Diverging map, varying lightness\n"
+                "  [-t|--type=pldiverging-saturation]  Diverging map, varying saturation\n"
+                "  [-t|--type=plqualitative-hue]       Qualitative map, evenly distributed hue\n"
+                "  [-l|--lightness=L]                  Set lightness in [0,1]\n"
+                "  [-s|--saturation=S]                 Set saturation in [0,1]\n"
+                "  [-h|--hue=H]                        Set default hue in [0,360] degrees\n"
+                "  [-d|--divergence=D]                 Set diverg. in deg for div. and qual. maps\n"
+                "  [-r|--rotations=R]                  Set number of rotations for rainbow maps\n"
+                "  [-T|--temperature=T]                Set start temp. in K for black body maps\n"
+                "  [-R|--range=R]                      Set temp. range in K for black body maps\n"
+                "CubeHelix color maps:\n"
+                "  [-t|--type=cubehelix]               Generate a CubeHelix color map\n"
+                "  [-h|--hue=H]                        Set start hue in [0,180] degrees\n"
+                "  [-r|--rotations=R]                  Set number of rotations, in (-infty,infty)\n"
+                "  [-s|--saturation=S]                 Set saturation, in [0,1]\n"
+                "  [-g|--gamma=G]                      Set gamma correction, in (0,infty)\n"
+                "Moreland diverging color maps:\n"
+                "  [-t|--type=moreland]                Generate a Moreland diverging color map\n"
+                "  [-A|--color0=sr,sg,sb]              Set the first color as sRGB in [0,255]\n"
+                "  [-O|--color1=sr,sg,sb]              Set the last color as sRGB in [0,255]\n"
+                "McNames sequential color maps:\n"
+                "  [-t|--type=mcnames]                 Generate a McNames sequential color map\n"
+                "  [-p|--periods=P]                    Set the number of periods in (0, infty)\n"
+                "Defaults: format=csv, n=256, type=brewer-sequential\n"
+                "https://marlam.de/gencolormap\n", argv[0]);
         return 0;
     }
 
-    if (type < 0) {
-        fprintf(stderr, "Invalid or missing option -t|--type.\n");
+    if (format < 0) {
+        fprintf(stderr, "Invalid argument for option -f|--format.\n");
         return 1;
     }
     if (n < 2) {
-        fprintf(stderr, "Invalid or missing option -n|--n.\n");
+        fprintf(stderr, "Invalid argument for option -n|--n.\n");
+        return 1;
+    }
+    if (type < 0) {
+        fprintf(stderr, "Invalid argument for option -t|--type.\n");
         return 1;
     }
     if (hue < 0.0f) {
@@ -267,6 +291,8 @@ int main(int argc, char* argv[])
             divergence = ColorMap::PLDivergingLightnessDefaultDivergence;
         else if (type == pldiv_saturation)
             divergence = ColorMap::PLDivergingSaturationDefaultDivergence;
+        else if (type == plqual_hue)
+            divergence = ColorMap::PLQualitativeHueDefaultDivergence;
     }
     if (contrast < 0.0f) {
         if (type == brewer_seq)
@@ -364,53 +390,61 @@ int main(int argc, char* argv[])
     }
 
     std::vector<unsigned char> colormap(3 * n);
+    int clipped;
     switch (type) {
     case brewer_seq:
-        ColorMap::BrewerSequential(n, &(colormap[0]), hue, contrast, saturation, brightness, warmth);
+        clipped = ColorMap::BrewerSequential(n, &(colormap[0]), hue, contrast, saturation, brightness, warmth);
         break;
     case brewer_div:
-        ColorMap::BrewerDiverging(n, &(colormap[0]), hue, divergence, contrast, saturation, brightness, warmth);
+        clipped = ColorMap::BrewerDiverging(n, &(colormap[0]), hue, divergence, contrast, saturation, brightness, warmth);
         break;
     case brewer_qual:
-        ColorMap::BrewerQualitative(n, &(colormap[0]), hue, divergence, contrast, saturation, brightness);
+        clipped = ColorMap::BrewerQualitative(n, &(colormap[0]), hue, divergence, contrast, saturation, brightness);
         break;
     case plseq_lightness:
-        ColorMap::PLSequentialLightness(n, &(colormap[0]), saturation, hue);
+        clipped = ColorMap::PLSequentialLightness(n, &(colormap[0]), saturation, hue);
         break;
     case plseq_saturation:
-        ColorMap::PLSequentialSaturation(n, &(colormap[0]), lightness, saturation, hue);
+        clipped = ColorMap::PLSequentialSaturation(n, &(colormap[0]), lightness, saturation, hue);
         break;
     case plseq_rainbow:
-        ColorMap::PLSequentialRainbow(n, &(colormap[0]), hue, rotations, saturation);
+        clipped = ColorMap::PLSequentialRainbow(n, &(colormap[0]), hue, rotations, saturation);
         break;
     case plseq_blackbody:
-        ColorMap::PLSequentialBlackBody(n, &(colormap[0]), temperature, range, saturation);
+        clipped = ColorMap::PLSequentialBlackBody(n, &(colormap[0]), temperature, range, saturation);
         break;
     case pldiv_lightness:
-        ColorMap::PLDivergingLightness(n, &(colormap[0]), lightness, saturation, hue, divergence);
+        clipped = ColorMap::PLDivergingLightness(n, &(colormap[0]), lightness, saturation, hue, divergence);
         break;
     case pldiv_saturation:
-        ColorMap::PLDivergingSaturation(n, &(colormap[0]), lightness, saturation, hue, divergence);
+        clipped = ColorMap::PLDivergingSaturation(n, &(colormap[0]), lightness, saturation, hue, divergence);
         break;
     case plqual_hue:
-        ColorMap::PLQualitativeHue(n, &(colormap[0]), lightness, saturation, hue);
+        clipped = ColorMap::PLQualitativeHue(n, &(colormap[0]), hue, divergence, lightness, saturation);
         break;
     case cubehelix:
-        ColorMap::CubeHelix(n, &(colormap[0]), hue, rotations, saturation, gamma);
+        clipped = ColorMap::CubeHelix(n, &(colormap[0]), hue, rotations, saturation, gamma);
         break;
     case moreland:
-        ColorMap::Moreland(n, &(colormap[0]),
+        clipped = ColorMap::Moreland(n, &(colormap[0]),
                 color0[0], color0[1], color0[2],
                 color1[0], color1[1], color1[2]);
         break;
     case mcnames:
-        ColorMap::McNames(n, &(colormap[0]), periods);
+        clipped = ColorMap::McNames(n, &(colormap[0]), periods);
         break;
     }
 
-    for (int i = 0; i < n; i++) {
-        printf("%d, %d, %d\n", colormap[3 * i + 0], colormap[3 * i + 1], colormap[3 * i + 2]);
+    std::string output;
+    if (format == csv) {
+        output = ColorMap::ToCSV(n, colormap.data());
+    } else if (format == json) {
+        output = ColorMap::ToJSON(n, colormap.data());
+    } else {
+        output = ColorMap::ToPPM(n, colormap.data());
     }
+    fputs(output.c_str(), stdout);
+    fprintf(stderr, "%d color(s) were clipped\n", clipped);
 
     return 0;
 }