summaryrefslogtreecommitdiffstats
path: root/util/gradientgen/gradientgen.js
blob: ff256d16d63aaf66709b7f90f4b3edda8e757aca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#! /usr/bin/env node

/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the utils of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

const _ = require('lodash');
const fs = require('fs');

const postcss = require('postcss');
const minifyGradients = require('postcss-minify-gradients');
const valueParser = require('postcss-value-parser');
const parseColor = require('parse-color');
const math = require('mathjs');

const argc = process.argv.length;
if (argc < 3) {
  console.log("usage: gradientgen [mode] <filename>");
  process.exit(1);
}

const filename = process.argv[argc - 1];
const mode = argc > 3 ? process.argv[argc - 2] : '';

fs.readFile(filename, (err, css) => {
  postcss([minifyGradients]).process(css)
    .then(result => {
      let enums = [];
      let gradients = [];

      result.root.walkRules(rule => {
        gradients.push(null); // Placeholder

        const name = _.startCase(rule.selector).replace(/\s/g, '');
        if (enums.indexOf(name) >= 0)
          return; // Duplicate entry

        // We can only support single gradient declarations
        if (rule.nodes.length > 1)
          return;

        valueParser(rule.nodes[0].value).walk(node => {
          if (node.type !== 'function')
            return;

          if (node.value !== 'linear-gradient')
            return;

          const args = node.nodes.reduce((args, arg) => {
              if (arg.type === 'div')
                args.push([]);
              else if (arg.type !== 'space')
                  args[args.length - 1].push(arg.value);
              return args;
          }, [[]]);

          let angle = valueParser.unit(args[0][0]);
          if (angle.unit !== 'deg')
            return;

          angle = parseInt(angle.number);
          if (angle < 0)
            angle += 360;

          // Angle is in degrees, but we need radians
          const radians = angle * math.pi / 180;

          const gradientLine = (math.abs(math.sin(radians)) + math.abs(math.cos(radians)));
          const cathetus = fn => math.round(fn(radians - math.pi / 2) * gradientLine / 2, 10);

          const x = cathetus(math.cos);
          const y = cathetus(math.sin);

          const start = { x: 0.5 - x, y: 0.5 - y };
          const end = { x: 0.5 + x, y: 0.5 + y };

          let stops = []
          args.slice(1).forEach((arg, index) => {
            let [color, stop = !index ? '0%' : '100%'] = arg;
            stop = parseInt(stop) / 100;
            color = parseColor(color).hex;
            color = parseInt(color.slice(1), 16)
            stops.push({ color, stop })
          });

          gradients[gradients.length - 1] = { start, end, stops };
        });

        enums.push(name);

        if (mode == 'enums')
          console.log(`${name} = ${gradients.length},`)
      });

      // Done walking declarations
      if (mode != 'enums')
        console.log(JSON.stringify(gradients, undefined, 4));
    });
});