summaryrefslogtreecommitdiff
path: root/xmerge/java/org/openoffice/xmerge/util/ColourConverter.java
blob: 345a4e76ef6f052cd71b386dcc732191b9a5cb01 (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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
/************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

package org.openoffice.xmerge.util;


import java.awt.Color;

/**
 * Utility class mapping RGB colour specifications to the colour indices used
 * in the Pocket PC. The original converter was written for use with Pocket
 * Word it was later put into the utils so Pocket excel could use this code
 * also. For this reason the defualt values are those used by Pocket Word but
 * a colour table can be passed in through the constructor to map the 16
 * values to a colour table.
 *
 * These colour indices are based on the Windows VGA 16 colour palette, which
 * later was used as the basis for the named colours in the HTML 3.2
 * specification.
 *
 * In Pocket Word's case, the match to the VGA 16 palette is not exact as it
 * swaps Grey and Silver, with Silver being the darker colour (i.e. having the
 * lower RGB value).
 */

public class ColourConverter {

    /** Colour table index for Black */
    private static final short BLACK = 0;

    /** Colour table index for Silver */
    private static final short SILVER = 1;

    /** Colour table index for Grey */
    private static final short GREY = 2;

    /** Colour table index for White */
    private static final short WHITE = 3;

    /** Colour table index for Red */
    private static final short RED = 4;

    /** Colour table index for Lime */
    private static final short LIME = 5;

    /** Colour table index for Blue */
    private static final short BLUE = 6;

    /** Colour table index for Aqua */
    private static final short AQUA = 7;

    /** Colour table index for Fuchsia */
    private static final short FUCHSIA = 8;

    /** Colour table index for Yellow */
    private static final short YELLOW = 9;

    /** Colour table index for Maroon */
    private static final short MAROON = 10;

    /** Colour table index for Green */
    private static final short GREEN = 11;

    /** Colour table index for Navy */
    private static final short NAVY = 12;

    /** Colour table index for Teal */
    private static final short TEAL = 13;

    /** Colour table index for Purple */
    private static final short PURPLE = 14;

    /** Colour table index for Olive */
    public static final short OLIVE = 15;

    private short tableLookup[] = null;

    /**
     * Default constructor used in the case where a lookup table is not
     * required
     */
    public ColourConverter() {

    }

    /**
     * Constructor that passes in the colour lookup table. This is required in
     * cases where the 16 colour values are something other than there default
     * values (e.g. in the case of pocket Excel)
     *
     * @param short[] a 16 bit array mapping the 16 colours to there values
     */
    public ColourConverter(short lookup[]) {

        tableLookup = lookup;
    }

    /**
     * Uses the colour table it it exists to translate default values to
     * values in the colorTable
     */
    private short colourLookup(short colour) {

        if(tableLookup!=null) {
            return tableLookup[colour];
        } else {
            return colour;
        }
    }

    /**
     * Uses the colour table it it exists to translate default values to
     * values in the colorTable
     */
    private short indexLookup(short index) {

        short result = 0;

        if(tableLookup!=null) {
            for(short i = 0;i < tableLookup.length;i++) {
                if(tableLookup[i]==index)
                    result = i;
            }
        } else {
            result = index;
        }

        return result;
    }
    /**
     * This method maps a Pocket Word colour index value to an RGB value as
     * used by OpenOffice.
     *
     * @param   index   The index into Pocket Word's colour table.
     *
     * @return  A Color object representing the RGB value of the Pocket Word
     *          colour.
     */
    public Color convertToRGB (short colour) {

        short index = indexLookup(colour);

        int r = 0;
        int g = 0;
        int b = 0;

        switch (index) {
            case SILVER:
                r = g = b = 128;
                break;

            case GREY:
                r = g = b = 192;
                break;

            case WHITE:
                r = g = b = 255;
                break;

            case RED:
                r = 255;
                break;

            case LIME:
                g = 255;
                break;

            case BLUE:
                b = 255;
                break;

            case AQUA:
                g = b = 255;
                break;

            case FUCHSIA:
                r = b = 255;
                break;

            case YELLOW:
                r = g = 255;
                break;

            case MAROON:
                r = 128;
                break;

            case GREEN:
                g = 128;
                break;

            case NAVY:
                b = 128;
                break;

            case TEAL:
                b = g = 128;
                break;

            case PURPLE:
                r = b = 128;
                break;

            case OLIVE:
                r = g = 128;
                break;

            case BLACK:
            default:
                r = g = b = 0;
                break;
        }

        return new Color(r, g, b);
    }


    /**
     * This method approximates an RGB value (as used by Writer) to one of the
     * 16 available colours
     *
     * Most of the supported colours have their components set to either 0, 128
     * or 255.  The exception is 'Grey' which is 0xC0C0C0.
     *
     * @param colour    Color object representing the RGB value of the colour.
     *
     * @return  Index into the Pocket Word colour table which represents the
     *          closest match to the specified colour.
     */
    public short convertFromRGB (Color colour) {
        int matchedRGB = 0;
        short indexColour = 0;
        int reducedMap[] =  new int[] { 0, 0, 128 };

          int red = colour.getRed();
          int green = colour.getGreen();
          int blue = colour.getBlue();

        // We need to convert the pale colors to their base color rather than
        // white so we modify the rgb values if the colour is sufficently
        // white
           if(red>0xC0 && green>0xC0 && blue>0xC0) {

            if(red!=0xFF)
                red = getClosest(red, reducedMap);
            if(green!=0xFF)
                green = getClosest(green, reducedMap);
            if(blue!=0xFF)
                blue = getClosest(blue, reducedMap);
        }

           /*
         * Need to derive an RGB value that has been rounded to match the ones
         * Pocket Word knows about.
            */
        matchedRGB += getClosest(red)   << 16;
        matchedRGB += getClosest(green) << 8;
           matchedRGB += getClosest(blue);

        /*
         * The colour map used by Pocket Word doesn't have any combinations of
         * values beyond 0 and any other value.  A value of 255 in any RGB
         * code indicates a dominant colour.  Other colours are only modifiers
         * to the principal colour(s).  Thus, for this conversion, modifiers
         * can be dropped.
         */
        if ((matchedRGB & 0xFF0000) == 0xFF0000 || (matchedRGB & 0xFF00) == 0xFF00
                || (matchedRGB & 0xFF) == 0xFF) {
                    if ((matchedRGB & 0xFF0000) == 0x800000) {
                        matchedRGB ^= 0x800000;
                    }
                    if ((matchedRGB & 0xFF00) == 0x8000) {
                        matchedRGB ^= 0x8000;
                    }
                    if ((matchedRGB & 0xFF) == 0x80) {
                        matchedRGB ^= 0x80;
                    }
        }


        /*
         * And now for the actual matching ...
         *
         * Colours are based on the Windows VGA 16 palette.  One difference
         * though is that Pocket Word seems to switch the RGB codes for Grey
         * and Silver.  In Pocket Word Silver is the darker colour leaving Grey
         * is closest to White.
         *
         * Shades of grey will be converted to either Silver or White, where
         * Grey may be a more appropraite colour.  This is handled specially
         * only for Silver and White matches.
         */
        switch (matchedRGB) {
            case 0x000000:
                indexColour = BLACK;
                break;

            case 0x808080:
                if (!isGrey(colour)) {
                    indexColour = SILVER;
                }
                else {
                    indexColour = GREY;
                }
                break;

            case 0xFFFFFF:
                if (!isGrey(colour)) {
                    indexColour = WHITE;
                }
                else {
                    indexColour = GREY;
                }
                break;

            case 0xFF0000:
                indexColour = RED;
                break;

            case 0x00FF00:
                indexColour = LIME;
                break;

            case 0x0000FF:
                indexColour = BLUE;
                break;

            case 0x00FFFF:
                indexColour = AQUA;
                break;

            case 0xFF00FF:
                indexColour = FUCHSIA;
                break;

            case 0xFFFF00:
                indexColour = YELLOW;
                break;

            case 0x800000:
                indexColour = MAROON;
                break;

            case 0x008000:
                indexColour = GREEN;
                break;

            case 0x000080:
                indexColour = NAVY;
                break;

            case 0x008080:
                indexColour = TEAL;
                break;

            case 0x800080:
                indexColour = PURPLE;
                break;

            case 0x808000:
                indexColour = OLIVE;
                break;

            default:        // Just in case!
                indexColour = BLACK;
                break;
        }

        return colourLookup(indexColour);
    }


    /*
     * Default implementation, checks for the closest of value to 0, 128 or 255.
     */
    private int getClosest(int value) {
        int points[] = new int[] { 0, 128, 255 };

        return getClosest(value, points);
    }


    /*
     * Utility method that returns the closest of the three points to the value
     * supplied.
     */
    private int getClosest(int value, int[] points) {

        if (value == points[0] || value == points[1] || value == points[2]) {
            return value;
        }

        if (value < points[1]) {
            int x = value - points[0];
            return (Math.round((float)x / (points[1] - points[0])) == 1 ? points[1] : points[0]);
        }
        else {
            int x = value - points[1];
            return (Math.round((float)x / (points[2] - points[1])) >= 1 ? points[2] : points[1]);
        }
    }


    /*
     * Checks to see if the supplied colour can be considered to be grey.
     */
    private boolean isGrey(Color c) {
        int matchedRGB = 0;
        int points[] = new int[] { 128, 192, 255 };

        matchedRGB += getClosest(c.getRed(), points) << 16;
        matchedRGB += getClosest(c.getGreen(), points) << 8;
        matchedRGB += getClosest(c.getBlue(), points);

        if (matchedRGB == 0xC0C0C0) {
            return true;
        }

        return false;
    }
}