pdfHTML: Colourblindness example

This is a code example of iText PDF, discover more.

8th March 2017
iText PDF
ColourBlindBlockCssApplier.java
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
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2019 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
package com.itextpdf.samples.pdfHTML.ColourBlindness;
 
import com.itextpdf.html2pdf.attach.ITagWorker;
import com.itextpdf.html2pdf.attach.ProcessorContext;
import com.itextpdf.html2pdf.css.CssConstants;
import com.itextpdf.html2pdf.css.apply.impl.BlockCssApplier;
import com.itextpdf.kernel.colors.WebColors;
import com.itextpdf.styledxmlparser.node.IStylesContainer;
 
import java.util.Map;
 
/**
 * Css applier extending from a blockcssapplier that transforms standard colours into the ones colourblind people see
 */
public class ColourBlindBlockCssApplier extends BlockCssApplier {
    private static final double RGB_MAX_VAL = 255.0;
    private String colourBlindness = ColourBlindnessTransforms.PROTANOPIA;
 
    /**
     * Set the from of colour blindness to simulate.
     * Accepted values are Protanopia, Protanomaly, Deuteranopia, Deuteranomaly, Tritanopia, Tritanomaly, Achromatopsia, Achromatomaly.
     * Default value is Protanopia
     * @param colourBlindness
     */
    public void setColourBlindness(String colourBlindness){
        this.colourBlindness = colourBlindness;
    }
 
    @Override
    public void apply(ProcessorContext context, IStylesContainer stylesContainer, ITagWorker tagWorker){
        Map<String, String> cssStyles = stylesContainer.getStyles();
        if(cssStyles.containsKey(CssConstants.COLOR)){
            String newColor = TransformColor(cssStyles.get(CssConstants.COLOR));
            cssStyles.put(CssConstants.COLOR,newColor);
            stylesContainer.setStyles(cssStyles);
        }
        if(cssStyles.containsKey(CssConstants.BACKGROUND_COLOR)){
            String newColor = TransformColor(cssStyles.get(CssConstants.BACKGROUND_COLOR));
            cssStyles.put(CssConstants.BACKGROUND_COLOR,newColor);
            stylesContainer.setStyles(cssStyles);
        }
        super.apply(context, stylesContainer,tagWorker);
 
    }
 
    private String TransformColor(String originalColor){
        //Array creation is a bit clumsy, could do with some cleaning
        float[] rgbaColor = WebColors.getRGBAColor(originalColor);
        float[] rgbColor = {rgbaColor[0],rgbaColor[1],rgbaColor[2]};
        float[] newColourRgb = ColourBlindnessTransforms.simulateColourBlindness(colourBlindness,rgbColor);
        float[] newColourRgba = {newColourRgb[0],newColourRgb[1],newColourRgb[2],rgbaColor[3]};
        double[] newColorArray = scaleColorFloatArray(newColourRgba);
        String newColorString = "rgba("+(int) newColorArray[0]+","+(int)newColorArray[1]+","+(int)newColorArray[2]+","+newColorArray[3]+")";
        return newColorString;
    }
 
    private double[] scaleColorFloatArray(float[] colors){
        double red = (colors[0]*RGB_MAX_VAL);
        double green =  (colors[1]*RGB_MAX_VAL);
        double blue =  (colors[2]*RGB_MAX_VAL);
        double[] res = {red,green, blue, (double) colors[3]};
        return res;
    }
 
 
}
ColourBlindSpanTagCssApplier.java
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
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2019 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
package com.itextpdf.samples.pdfHTML.ColourBlindness;
 
import com.itextpdf.html2pdf.attach.ITagWorker;
import com.itextpdf.html2pdf.attach.ProcessorContext;
import com.itextpdf.html2pdf.css.CssConstants;
import com.itextpdf.html2pdf.css.apply.impl.SpanTagCssApplier;
import com.itextpdf.kernel.colors.WebColors;
import com.itextpdf.styledxmlparser.node.IStylesContainer;
 
import java.util.Map;
 
public class ColourBlindSpanTagCssApplier extends SpanTagCssApplier {
 
    private static final double RGB_MAX_VAL = 255.0;
    private String colourBlindness = ColourBlindnessTransforms.PROTANOPIA;
 
    /**
     * Set the from of colour blindness to simulate.
     * Accepted values are Protanopia, Protanomaly, Deuteranopia, Deuteranomaly, Tritanopia, Tritanomaly, Achromatopsia, Achromatomaly.
     * Default value is Protanopia
     * @param colourBlindness
     */
    public void setColourBlindness(String colourBlindness){
        this.colourBlindness = colourBlindness;
    }
 
    @Override
    public void apply(ProcessorContext context, IStylesContainer stylesContainer, ITagWorker tagWorker){
        Map<String, String> cssStyles = stylesContainer.getStyles();
        if(cssStyles.containsKey(CssConstants.COLOR)){
            String newColor = TransformColor(cssStyles.get(CssConstants.COLOR));
            cssStyles.put(CssConstants.COLOR,newColor);
            stylesContainer.setStyles(cssStyles);
        }
        if(cssStyles.containsKey(CssConstants.BACKGROUND_COLOR)){
            String newColor = TransformColor(cssStyles.get(CssConstants.BACKGROUND_COLOR));
            cssStyles.put(CssConstants.BACKGROUND_COLOR,newColor);
            stylesContainer.setStyles(cssStyles);
        }
        super.apply(context, stylesContainer,tagWorker);
 
    }
 
    private String TransformColor(String originalColor){
        //Array creation is a bit clumsy, could do with some cleaning
        float[] rgbaColor = WebColors.getRGBAColor(originalColor);
        float[] rgbColor = {rgbaColor[0],rgbaColor[1],rgbaColor[2]};
        float[] newColourRgb = ColourBlindnessTransforms.simulateColourBlindness(colourBlindness,rgbColor);
        float[] newColourRgba = {newColourRgb[0],newColourRgb[1],newColourRgb[2],rgbaColor[3]};
        double[] newColorArray = scaleColorFloatArray(newColourRgba);
        String newColorString = "rgba("+(int) newColorArray[0]+","+(int)newColorArray[1]+","+(int)newColorArray[2]+","+newColorArray[3]+")";
        return newColorString;
    }
 
    private double[] scaleColorFloatArray(float[] colors){
        double red = (colors[0]*RGB_MAX_VAL);
        double green =  (colors[1]*RGB_MAX_VAL);
        double blue =  (colors[2]*RGB_MAX_VAL);
        double[] res = {red,green, blue, (double) colors[3]};
        return res;
    }
}
ColourBlindnessCssApplierFactory.java
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
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2019 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
package com.itextpdf.samples.pdfHTML.ColourBlindness;
 
 
import com.itextpdf.html2pdf.css.apply.ICssApplier;
import com.itextpdf.html2pdf.css.apply.impl.DefaultCssApplierFactory;
import com.itextpdf.html2pdf.html.TagConstants;
import com.itextpdf.styledxmlparser.node.IElementNode;
 
public class ColourBlindnessCssApplierFactory extends DefaultCssApplierFactory {
 
    private String toSimulate;
 
    public ColourBlindnessCssApplierFactory(String toSimulate){
        this.toSimulate = toSimulate;
    }
    @Override
    public ICssApplier getCustomCssApplier(IElementNode tag) {
        if(tag.name().equals(TagConstants.DIV)){
            ColourBlindBlockCssApplier applier =  new ColourBlindBlockCssApplier();
            applier.setColourBlindness(toSimulate);
            return applier;
        }
 
        if(tag.name().equals(TagConstants.SPAN)){
            ColourBlindSpanTagCssApplier applier =  new ColourBlindSpanTagCssApplier();
            applier.setColourBlindness(toSimulate);
            return applier;
        }
 
        return null;
    }
}
ColourBlindnessTransforms.java
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
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2019 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
package com.itextpdf.samples.pdfHTML.ColourBlindness;
 
public class ColourBlindnessTransforms {
/*
        Normal:{ R:[100, 0, 0], G:[0, 100, 0], B:[0, 100, 0]},
        Protanopia:{ R:[56.667, 43.333, 0], G:[55.833, 44.167, 0], B:[0, 24.167, 75.833]},
        Protanomaly:{ R:[81.667, 18.333, 0], G:[33.333, 66.667, 0], B:[0, 12.5, 87.5]},
        Deuteranopia:{ R:[62.5, 37.5, 0], G:[70, 30, 0], B:[0, 30, 70]},
        Deuteranomaly:{ R:[80, 20, 0], G:[25.833, 74.167, 0], B:[0, 14.167, 85.833]},
        Tritanopia:{ R:[95, 5, 0], G:[0, 43.333, 56.667], B:[0, 47.5, 52.5]},
        Tritanomaly:{ R:[96.667, 3.333, 0], G:[0, 73.333, 26.667], B:[0, 18.333, 81.667]},
        Achromatopsia:{ R:[29.9, 58.7, 11.4], G:[29.9, 58.7, 11.4], B:[29.9, 58.7, 11.4]},
        Achromatomaly:{ R:[61.8, 32, 6.2], G:[16.3, 77.5, 6.2], B:[16.3, 32.0, 51.6]}
*/
    public static final String PROTANOPIA = "Protanopia";
    private static float[][] PROTANOPIA_TRANSFORM = {{0.5667f,0.43333f,0},{0.55833f,0.44167f,0},{0,0.24167f,0.75833f}};
 
    public static final String PROTANOMALY = "Protanomaly";
    private static float[][] PROTANOMALY_TRANSFORM = {{0.81667f,0.18333f,0},{0.33333f,0.66667f,0},{0,0.125f,0.875f}};
 
    public static final String DEUTERANOPIA = "Deuteranopia";
    private static float[][] DEUTERANOPIA_TRANSFORM = {{0.625f,0.375f,0},{0.70f,0.30f,0},{0,0.30f,0.70f}};
 
    public static final String DEUTERANOMALY = "Deuteranomaly";
    private static float[][] DEUTERANOMALY_TRANSFORM = {{0.80f,0.20f,0},{0.25833f,0.74167f,0},{0,0.14167f,0.85833f}};
 
    public static final String TRITANOPIA = "Tritanopia";
    private static float[][] TRITANOPIA_TRANSFORM = {{0.95f,0.05f,0},{0,0.43333f,0.56667f},{0,0.475f,0.525f}};
 
    public static final String TRITANOMALY = "Tritanomaly";
    private static float[][] TRITANOMALY_TRANSFORM = {{0.96667f,0.0333f,0},{0,0.73333f,0.26667f},{0,0.18333f,0.81667f}};
 
    public static final String ACHROMATOPSIA = "Achromatopsia";
    private static float[][] ACHROMATOPSIA_TRANSFORM = {{0.299f,0.587f,0.114f},{0.299f,0.587f,0.114f},{0.299f,0.587f,0.114f}};
 
    public static final String ACHROMATOMALY = "Achromatomaly";
    private static float[][] ACHROMATOMALY_TRANSFORM = {{0.618f,0.32f,0.062f},{0.163f,0.775f,0.062f},{0.299f,0.587f,0.114f}};
 
 
    //Protanopia:{ R:[56.667, 43.333, 0], G:[55.833, 44.167, 0], B:[0, 24.167, 75.833]}
    public static float[] simulateProtanopia(float[] originalRgb){
        int nrOfChannels = 3; //R, G, B
        float[] result = new float[nrOfChannels];
        for(int i = 0; i<nrOfChannels;i++){
            result[i]=0;
            for(int j = 0; j<nrOfChannels;j++){
                result[i] += originalRgb[j]* PROTANOPIA_TRANSFORM[i][j];
            }
        }
        return result;
    }
 
    
    public static float[] simulateProtanomaly(float[] originalRgb){
        int nrOfChannels = 3; //R, G, B
        float[] result = new float[nrOfChannels];
        for(int i = 0; i<nrOfChannels;i++){
            result[i]=0;
            for(int j = 0; j<nrOfChannels;j++){
                result[i] += originalRgb[j]* PROTANOMALY_TRANSFORM[i][j];
            }
        }
        return result;
    }
 
    public static float[] simulateDeuteranopia(float[] originalRgb){
        int nrOfChannels = 3; //R, G, B
        float[] result = new float[nrOfChannels];
        for(int i = 0; i<nrOfChannels;i++){
            result[i]=0;
            for(int j = 0; j<nrOfChannels;j++){
                result[i] += originalRgb[j]* DEUTERANOPIA_TRANSFORM[i][j];
            }
        }
        return result;
    }
 
    public static float[] simulateDeuteranomaly(float[] originalRgb){
        int nrOfChannels = 3; //R, G, B
        float[] result = new float[nrOfChannels];
        for(int i = 0; i<nrOfChannels;i++){
            result[i]=0;
            for(int j = 0; j<nrOfChannels;j++){
                result[i] += originalRgb[j]* DEUTERANOMALY_TRANSFORM[i][j];
            }
        }
        return result;
    }
 
    public static float[] simulateTritanopia(float[] originalRgb){
        int nrOfChannels = 3; //R, G, B
        float[] result = new float[nrOfChannels];
        for(int i = 0; i<nrOfChannels;i++){
            result[i]=0;
            for(int j = 0; j<nrOfChannels;j++){
                result[i] += originalRgb[j]* TRITANOPIA_TRANSFORM[i][j];
            }
        }
        return result;
    }
 
    public static float[] simulateTritanomaly(float[] originalRgb){
        int nrOfChannels = 3; //R, G, B
        float[] result = new float[nrOfChannels];
        for(int i = 0; i<nrOfChannels;i++){
            result[i]=0;
            for(int j = 0; j<nrOfChannels;j++){
                result[i] += originalRgb[j]* TRITANOMALY_TRANSFORM[i][j];
            }
        }
        return result;
    }
 
    public static float[] simulateAchromatopsia(float[] originalRgb){
        int nrOfChannels = 3; //R, G, B
        float[] result = new float[nrOfChannels];
        for(int i = 0; i<nrOfChannels;i++){
            result[i]=0;
            for(int j = 0; j<nrOfChannels;j++){
                result[i] += originalRgb[j]* ACHROMATOPSIA_TRANSFORM[i][j];
            }
        }
        return result;
    }
 
    public static float[] simulateAchromatomaly(float[] originalRgb){
        int nrOfChannels = 3; //R, G, B
        float[] result = new float[nrOfChannels];
        for(int i = 0; i<nrOfChannels;i++){
            result[i]=0;
            for(int j = 0; j<nrOfChannels;j++){
                result[i] += originalRgb[j]* ACHROMATOMALY_TRANSFORM[i][j];
            }
        }
        return result;
    }
 
    //Input: string, float[3] with RGB colours
    //output: float[3] with modified RGB colours
    public static float[] simulateColourBlindness(String code, float[] originalRgb){
        switch(code){
            case PROTANOPIA:
                return simulateProtanopia(originalRgb);
            case PROTANOMALY:
                return simulateProtanomaly(originalRgb);
            case DEUTERANOPIA:
                return simulateDeuteranopia(originalRgb);
            case DEUTERANOMALY:
                return  simulateDeuteranomaly(originalRgb);
            case TRITANOPIA:
                return simulateTritanopia(originalRgb);
            case TRITANOMALY:
                return simulateTritanomaly(originalRgb);
            case ACHROMATOPSIA:
                return  simulateAchromatopsia(originalRgb);
            case ACHROMATOMALY:
                return simulateAchromatomaly(originalRgb);
            default:
                return originalRgb;
        }
    }
}


Contact

Still have questions? 

We're happy to answer your questions. Reach out to us and we'll get back to you shortly.

Contact us
Stay updated

Join 11,000+ subscribers and become an iText PDF expert by staying up to date with our new products, updates, tips, technical solutions and happenings.

Subscribe Now