David PHAM-VAN

Add support for CMYK, HSL anf HSV colors

1 # 1.2.0 1 # 1.2.0
2 * Change license to Apache 2.0 2 * Change license to Apache 2.0
3 * Improve PdfRect 3 * Improve PdfRect
  4 +* Add support for CMYK, HSL anf HSV colors
4 5
5 # 1.1.1 6 # 1.1.1
6 * Improve PdfPoint and PdfRect 7 * Improve PdfPoint and PdfRect
@@ -67,5 +67,219 @@ class PdfColor { @@ -67,5 +67,219 @@ class PdfColor {
67 (((b * 255.0).round() & 0xff) << 0)) & 67 (((b * 255.0).round() & 0xff) << 0)) &
68 0xFFFFFFFF; 68 0xFFFFFFFF;
69 69
  70 + PdfColorCmyk toCmyk() {
  71 + return PdfColorCmyk.fromRgb(r, g, b, a);
  72 + }
  73 +
  74 + PdfColorHsv toHsv() {
  75 + return PdfColorHsv.fromRgb(r, g, b, a);
  76 + }
  77 +
  78 + PdfColorHsl toHsl() {
  79 + return PdfColorHsl.fromRgb(r, g, b, a);
  80 + }
  81 +
  82 + static double _linearizeColorComponent(double component) {
  83 + if (component <= 0.03928) return component / 12.92;
  84 + return math.pow((component + 0.055) / 1.055, 2.4);
  85 + }
  86 +
  87 + double get luminance {
  88 + final double R = _linearizeColorComponent(r);
  89 + final double G = _linearizeColorComponent(g);
  90 + final double B = _linearizeColorComponent(b);
  91 + return 0.2126 * R + 0.7152 * G + 0.0722 * B;
  92 + }
  93 +
70 String toString() => "$runtimeType($r, $g, $b, $a)"; 94 String toString() => "$runtimeType($r, $g, $b, $a)";
71 } 95 }
  96 +
  97 +class PdfColorCmyk extends PdfColor {
  98 + final double c;
  99 + final double m;
  100 + final double y;
  101 + final double k;
  102 +
  103 + const PdfColorCmyk(this.c, this.m, this.y, this.k, [double a = 1.0])
  104 + : super(
  105 + (1.0 - c) * (1.0 - k),
  106 + (1.0 - m) * (1.0 - k),
  107 + (1.0 - y) * (1.0 - k),
  108 + );
  109 +
  110 + const PdfColorCmyk.fromRgb(double r, double g, double b, [double a = 1.0])
  111 + : k = 1.0 - r > g ? r : g > b ? r > g ? r : g : b,
  112 + c = (1.0 - r - (1.0 - r > g ? r : g > b ? r > g ? r : g : b)) /
  113 + (1.0 - (1.0 - r > g ? r : g > b ? r > g ? r : g : b)),
  114 + m = (1.0 - g - (1.0 - r > g ? r : g > b ? r > g ? r : g : b)) /
  115 + (1.0 - (1.0 - r > g ? r : g > b ? r > g ? r : g : b)),
  116 + y = (1.0 - b - (1.0 - r > g ? r : g > b ? r > g ? r : g : b)) /
  117 + (1.0 - (1.0 - r > g ? r : g > b ? r > g ? r : g : b)),
  118 + super(r, g, b, a);
  119 +
  120 + @override
  121 + PdfColorCmyk toCmyk() {
  122 + return this;
  123 + }
  124 +
  125 + String toString() => "$runtimeType($c, $m, $y, $k, $a)";
  126 +}
  127 +
  128 +double _getHue(
  129 + double red, double green, double blue, double max, double delta) {
  130 + double hue;
  131 + if (max == 0.0) {
  132 + hue = 0.0;
  133 + } else if (max == red) {
  134 + hue = 60.0 * (((green - blue) / delta) % 6);
  135 + } else if (max == green) {
  136 + hue = 60.0 * (((blue - red) / delta) + 2);
  137 + } else if (max == blue) {
  138 + hue = 60.0 * (((red - green) / delta) + 4);
  139 + }
  140 +
  141 + /// Set hue to 0.0 when red == green == blue.
  142 + hue = hue.isNaN ? 0.0 : hue;
  143 + return hue;
  144 +}
  145 +
  146 +class PdfColorHsv extends PdfColor {
  147 + final double hue;
  148 + final double saturation;
  149 + final double value;
  150 +
  151 + const PdfColorHsv._(this.hue, this.saturation, this.value, double red,
  152 + double green, double blue, double alpha)
  153 + : super(red, green, blue, alpha);
  154 +
  155 + factory PdfColorHsv(double hue, double saturation, double value,
  156 + [double alpha = 1.0]) {
  157 + final double chroma = saturation * value;
  158 + final double secondary =
  159 + chroma * (1.0 - (((hue / 60.0) % 2.0) - 1.0).abs());
  160 + final double match = value - chroma;
  161 +
  162 + double red;
  163 + double green;
  164 + double blue;
  165 + if (hue < 60.0) {
  166 + red = chroma;
  167 + green = secondary;
  168 + blue = 0.0;
  169 + } else if (hue < 120.0) {
  170 + red = secondary;
  171 + green = chroma;
  172 + blue = 0.0;
  173 + } else if (hue < 180.0) {
  174 + red = 0.0;
  175 + green = chroma;
  176 + blue = secondary;
  177 + } else if (hue < 240.0) {
  178 + red = 0.0;
  179 + green = secondary;
  180 + blue = chroma;
  181 + } else if (hue < 300.0) {
  182 + red = secondary;
  183 + green = 0.0;
  184 + blue = chroma;
  185 + } else {
  186 + red = chroma;
  187 + green = 0.0;
  188 + blue = secondary;
  189 + }
  190 +
  191 + return PdfColorHsv._(hue, saturation, value, red + match, green + match,
  192 + blue + match, alpha);
  193 + }
  194 +
  195 + factory PdfColorHsv.fromRgb(double red, double green, double blue,
  196 + [double alpha]) {
  197 + final double max = math.max(red, math.max(green, blue));
  198 + final double min = math.min(red, math.min(green, blue));
  199 + final double delta = max - min;
  200 +
  201 + final hue = _getHue(red, green, blue, max, delta);
  202 + final double saturation = max == 0.0 ? 0.0 : delta / max;
  203 +
  204 + return PdfColorHsv._(hue, saturation, max, red, green, blue, alpha);
  205 + }
  206 +
  207 + @override
  208 + PdfColorHsv toHsv() {
  209 + return this;
  210 + }
  211 +
  212 + String toString() => "$runtimeType($hue, $saturation, $value, $a)";
  213 +}
  214 +
  215 +class PdfColorHsl extends PdfColor {
  216 + final double hue;
  217 + final double saturation;
  218 + final double lightness;
  219 +
  220 + const PdfColorHsl._(this.hue, this.saturation, this.lightness, double alpha,
  221 + double red, double green, double blue)
  222 + : super(red, green, blue, alpha);
  223 +
  224 + factory PdfColorHsl(double hue, double saturation, double lightness,
  225 + [double alpha]) {
  226 + final double chroma = (1.0 - (2.0 * lightness - 1.0).abs()) * saturation;
  227 + final double secondary =
  228 + chroma * (1.0 - (((hue / 60.0) % 2.0) - 1.0).abs());
  229 + final double match = lightness - chroma / 2.0;
  230 +
  231 + double red;
  232 + double green;
  233 + double blue;
  234 + if (hue < 60.0) {
  235 + red = chroma;
  236 + green = secondary;
  237 + blue = 0.0;
  238 + } else if (hue < 120.0) {
  239 + red = secondary;
  240 + green = chroma;
  241 + blue = 0.0;
  242 + } else if (hue < 180.0) {
  243 + red = 0.0;
  244 + green = chroma;
  245 + blue = secondary;
  246 + } else if (hue < 240.0) {
  247 + red = 0.0;
  248 + green = secondary;
  249 + blue = chroma;
  250 + } else if (hue < 300.0) {
  251 + red = secondary;
  252 + green = 0.0;
  253 + blue = chroma;
  254 + } else {
  255 + red = chroma;
  256 + green = 0.0;
  257 + blue = secondary;
  258 + }
  259 + return PdfColorHsl._(hue, saturation, lightness, alpha, red + match,
  260 + green + match, blue + match);
  261 + }
  262 +
  263 + factory PdfColorHsl.fromRgb(double red, double green, double blue,
  264 + [double alpha]) {
  265 + final double max = math.max(red, math.max(green, blue));
  266 + final double min = math.min(red, math.min(green, blue));
  267 + final double delta = max - min;
  268 +
  269 + final double hue = _getHue(red, green, blue, max, delta);
  270 + final double lightness = (max + min) / 2.0;
  271 + // Saturation can exceed 1.0 with rounding errors, so clamp it.
  272 + final double saturation = lightness == 1.0
  273 + ? 0.0
  274 + : (delta / (1.0 - (2.0 * lightness - 1.0).abs())).clamp(0.0, 1.0);
  275 + return PdfColorHsl._(hue, saturation, lightness, alpha, red, green, blue);
  276 + }
  277 +
  278 + @override
  279 + PdfColorHsl toHsl() {
  280 + return this;
  281 + }
  282 +
  283 + @override
  284 + String toString() => '$runtimeType($hue, $saturation, $lightness, $a)';
  285 +}
@@ -182,10 +182,34 @@ class PdfGraphics { @@ -182,10 +182,34 @@ class PdfGraphics {
182 /// 182 ///
183 /// @param c Color to use 183 /// @param c Color to use
184 void setColor(PdfColor color) { 184 void setColor(PdfColor color) {
185 - buf.putNumList(<double>[color.r, color.g, color.b]);  
186 - buf.putString(" rg ");  
187 - buf.putNumList(<double>[color.r, color.g, color.b]);  
188 - buf.putString(" RG\n"); 185 + setFillColor(color);
  186 + setStrokeColor(color);
  187 + }
  188 +
  189 + /// Sets the fill color for drawing
  190 + ///
  191 + /// @param c Color to use
  192 + void setFillColor(PdfColor color) {
  193 + if (color is PdfColorCmyk) {
  194 + buf.putNumList(<double>[color.c, color.m, color.y, color.k]);
  195 + buf.putString(" k\n");
  196 + } else {
  197 + buf.putNumList(<double>[color.r, color.g, color.b]);
  198 + buf.putString(" rg\n");
  199 + }
  200 + }
  201 +
  202 + /// Sets the stroke color for drawing
  203 + ///
  204 + /// @param c Color to use
  205 + void setStrokeColor(PdfColor color) {
  206 + if (color is PdfColorCmyk) {
  207 + buf.putNumList(<double>[color.c, color.m, color.y, color.k]);
  208 + buf.putString(" K\n");
  209 + } else {
  210 + buf.putNumList(<double>[color.r, color.g, color.b]);
  211 + buf.putString(" RG\n");
  212 + }
189 } 213 }
190 214
191 /// Set the transformation Matrix 215 /// Set the transformation Matrix