Degree Project
colorXtractor – a technical aid for people with colour blindness
Stefan Hochwarter 2010-08-04 Subject: Computer Science Level: Bachelor Course code: 2DV00E
SE-351 95 Växjö / SE-391 82 Kalmar Tel +46-772-28 80 00 [email protected] Lnu.se
Abstract The aim of this thesis is to develop an technical aid (software) to help people with colour blindness. Colour blind people have difficulties to differentiate between certain colours, so the implemented software will name a selected colour. The software is implemented as a Mozilla Firefox extension and also uses a XPCOM component. Furthermore can the user select different colour databases and change the displaying properties. Keywords: colour blindness, Mozilla Firefox extension, Colour algorithms, CIELAB, accessibility
iii Contents
1. Introduction 1 1.1. Problem discussion ...... 1 1.2. Problem analysis ...... 2 1.3. Paper structure ...... 2
2. Background 3 2.1. Colour blindness ...... 3 2.1.1. Classification ...... 3 2.1.2. Diagnosis ...... 4 2.1.3. Treatment ...... 4 2.2. Colour blindness as a handicap ...... 4 2.2.1. Daily life ...... 4 2.2.2. Internet barriers ...... 5 2.3. Colour management ...... 7 2.3.1. Colour spaces ...... 7
3. Implementation 9 3.1. Features ...... 9 3.2. Used technologies ...... 10 3.2.1. XUL - XML User Interface Language ...... 11 3.2.2. CSS - Cascading Style Sheet ...... 11 3.2.3. JavaScript ...... 12 3.2.4. XPCOM – Cross Platform Component Object Model ...... 13 3.3. Colour algorithms ...... 15 3.3.1. RGB to CIELAB conversion ...... 15 3.3.2. Colour comparison algorithm ...... 16 3.4. Online Publication ...... 17
4. Conclusion 18 4.1. Analysis ...... 18 4.2. Final Discussion ...... 18 4.3. Future Work ...... 18
References 20
A. List of Abbreviations 22
B. List of Figures 23
C. List of Listings 24
D. Source code 25 D.1. The Mozilla Firefox extension ...... 25
iv D.2. The XPCOM Component ...... 42
v 1. Introduction This chapter of the thesis shall give a first overview of the paper and the topic, which will be discussed more detailed later on. It focuses mostly on the problem, which had to be solved.
1.1. Problem discussion The Internet is a very colourful place but for people suffering from colour blindness this fact could be a barrier. There is no treatment for this, but an aid could improve the accessibility of the Internet. Today there is no free and open-source software, which supports people suffering from colour blindness. About five percent of the population are suffering from colour blindness.[1] This means that they have problems to differentiate between certain colours and it leads to new Internet barriers when it comes to colours. Online-shopping, pie-charts or coloured status icons are just a few examples, so there is a need for an aid for those people, which can compensate the colour blindness. Figure 1.1 shows a symbolic representation. The left side illustrate the situation without any aid while at the right side an aid has been inserted and the information (e.g. a colour) can reach the user.
Figure 1.1: symbolic representation of an aid [30]
Actually I found the idea of this bachelor thesis originally from the “Project:Possibility Wiki” during my search for a topic: When shopping for clothes online, it’s hard for people with colourblindness to discern between different colours. Develop a browser-plugin (or a native app) that can help with this shopping scenario. This could also be useful when using Google Image Search.[16] The first decision to make was how it should be implemented. Finally I decided to implement a Mozilla Firefox extension. One reason for this decision was that Mozilla Firefox is the second most popular web browser (behind Microsoft Internet Explorer).[3] So it is the most used open source browser which offers a great documentation and com- munity for writing extensions. Another reason for solving this problem as an extension is that the user does not need to run a stand alone software. The extension is nicely integrated in the graphical user interface of Firefox. Furthermore the extension can be designed platform independent (apart from the XPCOM component).
1 1.2. Problem analysis So I decided to create a technical aid for people with colour blindness, which is imple- mented as a Mozilla Firefox extension. Before I started to write the extension, I set some goals which it should fulfil.
1. The basic feature of the extension is to name a selected colour.
2. Follow the KISS principle. KISS is a design principle and stands for “keep it simple and stupid”. The extension should be easy to use and not distract the user from his/her actual work.
3. The software should be platform independent. In other words, everywhere where Mozilla Firefox runs, the extension should work as well.
4. colorXtractor should be open source, so the source code can be reused.
5. i18n – internationalisation should be realised.
1.3. Paper structure This paper exists in two main parts. The first part will focus on the problem, namely on defective colour vision and how it affects people who are suffering from it. The second part will concentrate on the problem solving. This is mostly about the written extension, the used technologies and some interesting algorithms.
2 2. Background This chapter will provide the essential background information for writing the aid for people with colour blindness. The first part is about colour blindness in general and how it can be classified. As the extension should help people, this section will also show, why and in which way colour blindness can be a handicap. For the implementation it is also important, to know some colour spaces - each with its advantages and disadvantages.
2.1. Colour blindness Colour blindness was first scientificly documented by the English chemist, John Dalton. After he realised that he suffered from colour blindness, he published a paper on this subject in 1798: ”Extraordinary facts relating to the vision of colours”. Because of this work, colour blindness is often called Daltonism. Nowadays, Daltonism stands only for one certain type of colour blindness (deuteranopia).[1]
2.1.1. Classification Colour blindness can be classified by clinical appearance. Generally it can be differed between total colour blindness (achromatopsia) and partial colour blindness or defective colour vision.
• total colour blindness (achromatopsia)
• partial colour blindness – red / green colour deficit ∗ anomalous trichromacy (protanomaly and deuteranomaly) ∗ dichromatopsia (protanopia and deuteranopia) – blue / yellow colour deficit ∗ anomalous trichromacy (tritanomaly) ∗ dichromatopsia (tritanopia)
Total colour blindness Persons who suffer from total colour blindness can only experience different light inten- sities but no colours. It is very rare, only 0.01 % people are affected. Possible causes are cone aplasia, cone dystrophy, retina diseases, albinism or cortex diseases.[1]
Partial colour blindness This quite common disease affects mostly men (8% men, 1% woman). Beside the classifi- cation of clinical appearance you can also differentiate between inheritance and acquired colour blindness. Anomalous trichromacy is a reduced sense for red (protanomaly), green (deutera- nomaly, 50 % of the inheritance cases) or blue (tritanomaly, rare).
3 The absence of one of the three retinal cones, which are essential for colour vision, is called dichromatopsia. It leads to the typical colour confusions. This is discerned again by the three colours red, green and blue. If the missing colour is red, the disease is called protanopia. This leads to red / green colour deficit. Deuteranopia also leads to red / green colour deficit, but the missing colour is green. When blue is missing, it is called tritanopia and it leads to blue / yellow deficit. Tritanopia is very rare. When two colours are missing, it is called monochromaticity.[1]
2.1.2. Diagnosis To diagnose colour blindness, qualitative clinical tests are used. The most common tests are the Stilling colour test, the Ishihara colour test and the Farnsworth panel D15 test.[1]
(a) Ishihara colour test [6] (b) Farnsworth D15 colour test [10]
Figure 2.1: Colour blindness tests
2.1.3. Treatment There is no medical treatment to cure people suffering from colour blindness. However, there exists some aid for people with colour blindness. Gnome offers a library, which provides a pixel filter, according to the user’s colour blindness.[14] Another non-technical aid are contact lenses designed for people with colour blindness.[4]
2.2. Colour blindness as a handicap When it comes to daily life, colour blindness can be a big handicap. In the following section I will list some examples.
2.2.1. Daily life As my extension focuses on web accessibility, I will keep this section short. But I want to deliver insight into the world of people with colour blindness. This is best done with examples. On the first picture you can see bananas and it is clear to see which are ripe.
4 The second picture is the same, but deuteranopia is simulated. As you can see it is impossible to differentiate between ripe and unripe bananas.
(a) original (b) deuteranopia
Figure 2.2: Comparision of bananas [5]
Another example are LED lights, used in devices to indicate something. The left picture is again the original and in the right picture protanopia was simulated.
(a) original [18] (b) protanopia
Figure 2.3: Comparison of LED lights
2.2.2. Internet barriers As the goal of the extension is to help people with colour blindness in the web, I want to show examples where colours can be a barrier. For people suffering from colour blindness, it can be hard or impossible to interpret a statistic when colours are the only source for matching the value to the graph. Figure 2.4 shows a pie chart, once original and once with deuteranopia simulated.
5 (a) original [2] (b) deuteranopia
Figure 2.4: Comparison of a pie chart
Online-shopping is another example where people with colour blindness may have some difficulties. When they want to order some furniture which should fit with their interior, they need to order it in a certain colour. It is also the same with clothes. Figure 2.5 shows a screenshot of an online-shop, on the right again with deuteranopia simulated.
(a) original [24] (b) deuteranopia
Figure 2.5: Comparison of an online shop
Also status icons, which indicate if a user is online, are often just coloured shapes. For people suffering from colour blindness it can be hard to say if a user is on- or offline. See figure 2.6.
6 (a) original [11] (b) deuteranopia
Figure 2.6: Comparison of icq status icons
2.3. Colour management I worked mostly with two colour models, the RGB and the CIELAB colour model. This section will give a insight into those models.
2.3.1. Colour spaces The extension explains two different colour spaces, namely the RGB colour space and the CIELAB colour space.
RGB colour model RGB stands for red, green and blue and the model adds those three colours to produce a certain colour. The RGB colour model is a additive colour model and it is based on a Cartesian coordinate system. It is a very common system for displaying images in electronic systems. The disadvantage of the RGB colour model is, that it is device- dependent. This means that the presentation of a RGB value may vary on different devices. Figure 2.7 illustrates the RGB colour model. [17] [18]
Figure 2.7: RGB colour model [19]
CIELAB CIE L*a*b* is a colour opponent space and it describes all colours visible to the human eye. L describes the lightness, a is the position on the red-green axis and b the position on the yellow-blue axis. Unlike the RGB colour model, it is device-independent. Figure 2.8 shows the CIE L*a*b* colour space. [20] [13]
7 Figure 2.8: CIE L*a*b* colour space [22]
8 3. Implementation The project behind this thesis is called colorXtractor. This Mozilla Firefox extension helps people with colour blindness to distinguish colours. Figure 3.1 shows colorXtractor in action. At the left bottom edge is the extension’s icon. Next to the icon is the calculated colour name.
Figure 3.1: colorXtractor - screenshot
Because this is my first Mozilla Firefox extension, I had to learn how to use the technologies and how they interact. Therefor I read mostly on the Mozilla Develeoper Center and used the extension "Colorzilla"[21] as a template for starting. Unfortunately there was no good and up-to-date tutorial / document about a XPCOM extension, so this part was very time consuming.
3.1. Features The main feature of the extension is to display a colour under the mouse cursor, after clicking on the extension’s icon. The first step is to get the pixel’s colour code, format it and find the closest matching colour from a colour database. The user can also change some options. He or she can select between different colour databases and format the colour string. The RGB, HSL and CIELAB colour values and the x-y coordinates can be displayed.
9 Figure 3.2: colorXtractor - options
3.2. Used technologies A Mozilla Firefox extension is basically a package of files, that influences the appear- ance and behaviour of Firefox. This package is simply created by zipping all files and changing the the file extension to “xpi”. The package of colorXtractor has the following structure.[9]
Listing 3.1: Package structure |-- chrome.manifest // chrome registration manifest |-- components // component and XPT files |-- content // files for overlay and JavaScripts |-- defaults | ‘-- preferences // default preferences |-- install.rdf // extension install manifest |-- locale // i18n |-- platform // platform specific directory ‘-- skin // skin directory (CSS)
For building a simple Firefox extension, there are only three basic technologies needed. CSS (Cascading Style Sheets) is used for skinning, JavaScript for behaviour and XUL (XML User Interface Language) for the user interface. For more complex extension it is necessary to use XPCOM (Cross Platform Component Object Model), which provides additional functionality.[23]
10 Figure 3.3: role of each technology in Firefox [15]
3.2.1. XUL - XML User Interface Language XUL was developed by Mozilla for describing the Graphical User Interface (GUI) of Firefox. As it is XML based, it uses tags like
Listing D.9: colorxtractorUtils.js // register the XPCom component function cxInitComponent(){ try{ const cid = "@sourceforge.net/projects/ColorReader;1"; gCXComponent = Components.classes[cid].createInstance(); gCXComponent = gCXComponent.QueryInterface(Components.interfaces.
34 IColorReader); } catch(err) { dump("colorXtractor: Could not get object: " + err + "\n" + cid); return; }
// use the first color database cxInitColorDatabase(gCXdbnames[0]); } function cxInitColorDatabase(dbname){
eval("gCXnames = " + dbname + ";"); // add rgb and hsl values to the color-array var color, lab; for (var i = 0; i < gCXnames.length; i++) { color = gCXnames[i][1]; lab = cxGetLab(color); gCXnames[i].push(lab[0], lab[1], lab[2]); // columns of new color-array: name - rgb(hex) - L - a - b } }
// calls the XPCom method for getting the color at x,y, returns rgb hex value function cxGetColor(x, y){
var bbggrr, rrggbb; // COLORREF has the format bbggrr, but we work with rrggbb bbggrr = gCXComponent.getPixelColor(x, y); // so we need to transfrom it var r, g, b; r = bbggrr & parseInt(0x0000ff); g = bbggrr & parseInt(0x00ff00); b = bbggrr & parseInt(0xff0000);
b = b >> 16; r = r << 16;
rrggbb = r | g | b;
return rrggbb; }
// find closest color with cie-lab function cxGetColorName(color){
var lab = cxGetLab(color); var l = lab[0], a = lab[1], b = lab[2];
35 var dif = -1, ndif = 0, cl = -1;
for (var i = 0; i < gCXnames.length; i++) { if (color == gCXnames[i][1]) return gCXnames[i][0];
ndif = Math.pow(Math.pow(l - gCXnames[i][2], 2) + Math.pow(a - gCXnames[i][3], 2) + Math.pow(b - gCXnames[i][4], 2),1/2);
if (dif < 0 || dif > ndif){ dif = ndif; cl = i; } } return gCXnames[cl][0]; }
// opens the about dialog function cxOpenAboutDialog() { window.open(’chrome://colorxtractor/content/about.xul’,’’,’chrome, centerscreen’); }
// opens a url in a new tab, used for project homepage and documentation function cxGoToURL(url) { var win = cxGetBrowserWindow(); if (win) win.getBrowser().selectedTab = win.getBrowser().addTab(url); // we are here because we either wanted to open in new // window, or wanted to open in tab, but couldn’t find browser window else openDialog("chrome://browser/content/browser.xul", "_blank", " chrome,all,dialog=no", url, null, null); }
// needed for cxGoToUrl(url) function cxGetBrowserWindow() { if (window.getBrowser) { return window; }
var browserWindowType = "navigator:browser";
var wm = Components.classes["@mozilla.org/appshell/window-mediator ;1"] .getService(Components.interfaces.nsIWindowMediator );
var win = wm.getMostRecentWindow(browserWindowType, true);
36 if (win && win.toolbar.visible) { return win; }
// else var windows = wm.getEnumerator(browserWindowType, true); while (windows.hasMoreElements()) { win = windows.getNext(); if (win.toolbar.visible) { return win; } }
return null; }
// gets the color and formats it for the status-bar function cxSetStatusBarString(){
var text = "";
// get the color at x,y var color = cxGetColor(gCXSelectedX, gCXSelectedY); // find the closest color-name var cname = cxGetColorName(color);
// read the options var showRGB = document.getElementById(’colorxtractor-menu-rgb’); var showHSL = document.getElementById(’colorxtractor-menu-hsl’); var showXY = document.getElementById(’colorxtractor-menu-xy’); var showLab = document.getElementById(’colorxtractor-menu-lab’);
// colorname always displayed text += cname;
// add rgb info if (showRGB.getAttribute(’checked’) == ’true’) { var rgb = cxGetRGB(color); text += " | R: " + rgb[0] + ", G: " + rgb[1] + ", B: " + rgb[2]; }
// add hsl info if (showHSL.getAttribute(’checked’) == ’true’) { var hsl = cxGetHSL(color); var hDegree = Math.round(hsl[0] * 3600) / 10; if (hDegree < 0) hDegree += 360; text += " | H: " + hDegree + ", S: " + Math.round(hsl[1] * 100) / 100 + ", L: " + Math.round(hsl[2] * 100) / 100;
37 }
// add Lab info if (showLab.getAttribute(’checked’) == ’true’) { var lab = cxGetLab(color); text += " | L: " + Math.round(lab[0] *1000) / 1000 + ", a: " + Math .round(lab[1] *1000) / 1000 + ", b: " + Math.round(lab[2] *1000) / 1000;
}
// add coordinates if (showXY.getAttribute(’checked’) == ’true’) { var rgb = cxGetRGB(color); text += " | X: " + gCXSelectedX + ", Y: " + gCXSelectedY; }
// sets the string gCXStatusBarString = text;
}
// returns an Lab-array function cxGetLab(color) {
var X, Y, Z; // rgb in percent (255 decimal = ff hexadecimal) var r, g, b; var rgb = cxGetRGB(color); r = rgb[0] / 255; g = rgb[1] / 255; b = rgb[2] / 255;
// RGB to XYZ if (r > 0.04045) r = Math.pow(((r + 0.055) / 1.055), 2.4); else r = r / 12.92; if (g > 0.04045) g = Math.pow(((g + 0.055) / 1.055), 2.4); else g = g / 12.92; if (b > 0.04045) b = Math.pow(((b + 0.055) / 1.055), 2.4); else b = b / 12.92;
r = r * 100; g = g * 100;
38 b = b * 100;
//Observer = 2 degrees, Illuminant = D65 X = r * 0.4124 + g * 0.3576 + b * 0.1805; Y = r * 0.2126 + g * 0.7152 + b * 0.0722; Z = r * 0.0193 + g * 0.1192 + b * 0.9505;
// now XYZ to Lab, again with //Observer = 2 degrees, Illuminant = D65 var Xr = 95.047, Yr = 100.00, Zr = 108.883; var xr = X / Xr; var yr = Y / Yr; var zr = Z / Zr;
var fx, fy, fz; var L, a, b1;
var e = 216 / 24389; var k = 24389 / 27;
if (xr > e) fx = Math.pow(xr, 1/3); else fx = (k * xr + 16) / 116; if (yr > e) fy = Math.pow(yr, 1/3); else fy = (k * yr + 16) / 116; if (zr > e) fz = Math.pow(zr, 1/3); else fz = (k * zr + 16) / 116;
L = 116 * fy - 16; a = 500 * (fx - fy); b1 = 200 * (fy - fz);
return [L, a, b1]; }
// returns a rgb-array (hex values) of color, input-format: 0xrrggbb, may be a number or a string function cxGetRGB(color) {
var rgb = [0, 0, 0];
// color is a string if (typeof color == ’string’) rgb = [parseInt(color.substring(0, 2) ,16), parseInt(color. substring(2, 4), 16), parseInt(color.substring(4, 6), 16)];
39 // color is a number if (typeof color == ’number’){ var r = color & parseInt(0xFF0000); r = r >> 16; var g = color & parseInt(0x00FF00); g = g >> 8; var b = color & parseInt(0x0000FF); rgb = [r, g, b]; } return rgb; }
// returns a hsl-array (percent-values) of color function cxGetHSL(color){ // good docu: http://130.113.54.154/~monger/hsl-rgb.html
// rgb in percent (255 decimal = ff hexadecimal) var r, g, b; var rgb = cxGetRGB(color); r = rgb[0] / 255; g = rgb[1] / 255; b = rgb[2] / 255; var max, min; var h, s, l;
max = Math.max(r, g, b); min = Math.min(r, g, b); var delta = max - min;
// calculate luminance l l = (max + min) / 2;
if (max == min){ s = 0; h = 0; return [h, s, l]; }
// calculate saturation s if (l < 0.5) s = delta / (max + min); else if (l >= 0.5) s = delta / (2.0 - max - min);
// calculate hue h if (r == max) h = (g - b) / delta; else if (g == max) h = 2.0 + (b - r) / delta; else if (b == max) h = 4.0 + (r - g) / delta;
40 h /= 6;
return [h, s, l]; }
Listing D.10: colorxtractor.js // See http://kb.mozillazine.org/Localize_extension_descriptions pref("extensions.colorxtractor@s.hochwarter.description", "chrome:// colorxtractor/locale/colorxtractor.properties");
Listing D.11: about.dtd
Listing D.12: colorxtractor.dtd
Listing D.13: colorxtractor.properties extensions.colorxtractor.description=colorXtractor is an extension for Mozilla Firefox, which is written for people with color-blindness. The extension shows the color of a selected area as text.
Listing D.14: colorxtractor.css #colorxtractor-status-bar-color { -moz-appearance: none !important; background-image: url("chrome://colorxtractor/skin/main-icon.png"); border: 1px inset;
41 background-repeat: no-repeat; background-position: top left; padding: 0; margin: 0; }
D.2. The XPCOM Component
Listing D.15: Folder structure . |-- ColorReader.cpp |-- ColorReader.h |-- ColorReaderModule.cpp |-- IColorReader.h |-- IColorReader.idl
Listing D.16: IColorReader.idl
/* * DO NOT EDIT. THIS FILE IS GENERATED FROM .\IColorReader.idl */
#ifndef __gen_IColorReader_h__ #define __gen_IColorReader_h__
#ifndef __gen_nsISupports_h__ #include "nsISupports.h" #endif
/* For IDL files that don’t want to include root IDL files. */ #ifndef NS_NO_VTABLE #define NS_NO_VTABLE #endif
/* starting interface: IColorReader */ #define ICOLORREADER_IID_STR "b146175f-a35d-4f59-9d2c-7eb828879299"
#define ICOLORREADER_IID \ {0xb146175f, 0xa35d, 0x4f59, \ { 0x9d, 0x2c, 0x7e, 0xb8, 0x28, 0x87, 0x92, 0x99 }}
class NS_NO_VTABLE NS_SCRIPTABLE IColorReader : public nsISupports { public:
NS_DECLARE_STATIC_IID_ACCESSOR(ICOLORREADER_IID)
/* unsigned long getPixelColor (in long x, in long y); */ NS_SCRIPTABLE NS_IMETHOD GetPixelColor(PRInt32 x, PRInt32 y, PRUint32 *_retval NS_OUTPARAM) = 0;
42 };
NS_DEFINE_STATIC_IID_ACCESSOR(IColorReader, ICOLORREADER_IID)
/* Use this macro when declaring classes that implement this interface. */ #define NS_DECL_ICOLORREADER \ NS_SCRIPTABLE NS_IMETHOD GetPixelColor(PRInt32 x, PRInt32 y, PRUint32 *_retval NS_OUTPARAM);
/* Use this macro to declare functions that forward the behavior of this interface to another object. */ #define NS_FORWARD_ICOLORREADER(_to) \ NS_SCRIPTABLE NS_IMETHOD GetPixelColor(PRInt32 x, PRInt32 y, PRUint32 *_retval NS_OUTPARAM) { return _to GetPixelColor(x, y, _retval); }
/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */ #define NS_FORWARD_SAFE_ICOLORREADER(_to) \ NS_SCRIPTABLE NS_IMETHOD GetPixelColor(PRInt32 x, PRInt32 y, PRUint32 *_retval NS_OUTPARAM) { return !_to ? NS_ERROR_NULL_POINTER : _to ->GetPixelColor(x, y, _retval); }
#if 0 /* Use the code below as a template for the implementation class for this interface. */
/* Header file */ class _MYCLASS_ : public IColorReader { public: NS_DECL_ISUPPORTS NS_DECL_ICOLORREADER
_MYCLASS_(); private: ~_MYCLASS_(); protected: /* additional members */ };
/* Implementation file */ NS_IMPL_ISUPPORTS1(_MYCLASS_, IColorReader)
_MYCLASS_::_MYCLASS_() { /* member initializers and constructor code */ }
43 _MYCLASS_::~_MYCLASS_() { /* destructor code */ }
/* unsigned long getPixelColor (in long x, in long y); */ NS_IMETHODIMP _MYCLASS_::GetPixelColor(PRInt32 x, PRInt32 y, PRUint32 * _retval NS_OUTPARAM) { return NS_ERROR_NOT_IMPLEMENTED; }
/* End of implementation class template. */ #endif
#endif /* __gen_IColorReader_h__ */
Listing D.17: IColorReader.h
/* * DO NOT EDIT. THIS FILE IS GENERATED FROM .\IColorReader.idl */
#ifndef __gen_IColorReader_h__ #define __gen_IColorReader_h__
#ifndef __gen_nsISupports_h__ #include "nsISupports.h" #endif
/* For IDL files that don’t want to include root IDL files. */ #ifndef NS_NO_VTABLE #define NS_NO_VTABLE #endif
/* starting interface: IColorReader */ #define ICOLORREADER_IID_STR "b146175f-a35d-4f59-9d2c-7eb828879299"
#define ICOLORREADER_IID \ {0xb146175f, 0xa35d, 0x4f59, \ { 0x9d, 0x2c, 0x7e, 0xb8, 0x28, 0x87, 0x92, 0x99 }} class NS_NO_VTABLE NS_SCRIPTABLE IColorReader : public nsISupports { public:
NS_DECLARE_STATIC_IID_ACCESSOR(ICOLORREADER_IID)
/* unsigned long getPixelColor (in long x, in long y); */ NS_SCRIPTABLE NS_IMETHOD GetPixelColor(PRInt32 x, PRInt32 y, PRUint32 *_retval NS_OUTPARAM) = 0;
44 };
NS_DEFINE_STATIC_IID_ACCESSOR(IColorReader, ICOLORREADER_IID)
/* Use this macro when declaring classes that implement this interface. */ #define NS_DECL_ICOLORREADER \ NS_SCRIPTABLE NS_IMETHOD GetPixelColor(PRInt32 x, PRInt32 y, PRUint32 *_retval NS_OUTPARAM);
/* Use this macro to declare functions that forward the behavior of this interface to another object. */ #define NS_FORWARD_ICOLORREADER(_to) \ NS_SCRIPTABLE NS_IMETHOD GetPixelColor(PRInt32 x, PRInt32 y, PRUint32 *_retval NS_OUTPARAM) { return _to GetPixelColor(x, y, _retval); }
/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */ #define NS_FORWARD_SAFE_ICOLORREADER(_to) \ NS_SCRIPTABLE NS_IMETHOD GetPixelColor(PRInt32 x, PRInt32 y, PRUint32 *_retval NS_OUTPARAM) { return !_to ? NS_ERROR_NULL_POINTER : _to ->GetPixelColor(x, y, _retval); }
#if 0 /* Use the code below as a template for the implementation class for this interface. */
/* Header file */ class _MYCLASS_ : public IColorReader { public: NS_DECL_ISUPPORTS NS_DECL_ICOLORREADER
_MYCLASS_(); private: ~_MYCLASS_(); protected: /* additional members */ };
/* Implementation file */ NS_IMPL_ISUPPORTS1(_MYCLASS_, IColorReader)
_MYCLASS_::_MYCLASS_() { /* member initializers and constructor code */ }
45 _MYCLASS_::~_MYCLASS_() { /* destructor code */ }
/* unsigned long getPixelColor (in long x, in long y); */ NS_IMETHODIMP _MYCLASS_::GetPixelColor(PRInt32 x, PRInt32 y, PRUint32 * _retval NS_OUTPARAM) { return NS_ERROR_NOT_IMPLEMENTED; }
/* End of implementation class template. */ #endif
#endif /* __gen_IColorReader_h__ */
Listing D.18: ColorReader.h #ifndef _COLOR_READER_H_ #define _COLOR_READER_H_
#include "IColorReader.h"
#define COLOR_READER_CONTRACTID "@sourceforge.net/projects/ColorReader ;1" #define COLOR_READER_CLASSNAME "Gets the Color of a Pixel (x,y)" #define COLOR_READER_CID { 0xb146175f, 0xa35d, 0x4f59, \ { 0x9d, 0x2c, 0x7e, 0xb8, 0x28, 0x87, 0x92, 0x99 } } class ColorReader : public IColorReader { public: NS_DECL_ISUPPORTS NS_DECL_ICOLORREADER
ColorReader(); private: ~ColorReader(); protected: /* additional members */ };
#endif _COLOR_READER_H_
Listing D.19: ColorReader.cpp #include "ColorReader.h"
46 #include "xpcom-config.h" #include
/* Implementation file */ NS_IMPL_ISUPPORTS1(ColorReader, IColorReader)
ColorReader::ColorReader() { /* member initializers and constructor code */ }
ColorReader::~ColorReader() { /* destructor code */ }
/* unsigned long getPixelColor (in long x, in long y); - color of pixel(x,y) - format: 0x00bbggrr (b...blue, g...green, r... red) - null if failure*/ NS_IMETHODIMP ColorReader::GetPixelColor(PRInt32 x, PRInt32 y, PRUint32 *_retval NS_OUTPARAM) { // GetDC: The handle the device context for the specified window’s client area indicates success. NULL indicates failure HDC dc = GetDC(0);
// Get the Color (RGB) at (x,y) // COLORREF: DWORD 32 bit unsigned long // format: 0x00bbggrr if (dc != NULL){
COLORREF color = GetPixel(dc, x, y);
*_retval = (unsigned long) color; return NS_OK; }
*_retval = NULL; return NS_OK;
}
/* End of implementation class template. */
Listing D.20: ColorReaderModule.cpp #include "nsIGenericFactory.h" #include "xpcom-config.h" #include "ColorReader.h"
47 NS_GENERIC_FACTORY_CONSTRUCTOR(ColorReader) static nsModuleComponentInfo components[] = { { COLOR_READER_CLASSNAME, COLOR_READER_CID, COLOR_READER_CONTRACTID, ColorReaderConstructor, } };
NS_IMPL_NSGETMODULE("ColorReaderModule", components)
48