Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor annotation color handling and add unit tests #6214

Merged
merged 1 commit into from Jul 16, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
68 changes: 45 additions & 23 deletions src/core/annotation.js
Expand Up @@ -17,7 +17,7 @@
/* globals PDFJS, Util, isDict, isName, stringToPDFString, warn, Dict, Stream,
stringToBytes, Promise, isArray, ObjectLoader, OperatorList,
isValidUrl, OPS, createPromiseCapability, AnnotationType,
stringToUTF8String, AnnotationBorderStyleType */
stringToUTF8String, AnnotationBorderStyleType, ColorSpace */

'use strict';

Expand Down Expand Up @@ -79,28 +79,8 @@ var Annotation = (function AnnotationClosure() {
data.rect = Util.normalizeRect(rect);
data.annotationFlags = dict.get('F');

var color = dict.get('C');
if (!color) {
// The PDF spec does not mention how a missing color array is interpreted.
// Adobe Reader seems to default to black in this case.
data.color = [0, 0, 0];
} else if (isArray(color)) {
switch (color.length) {
case 0:
// Empty array denotes transparent border.
data.color = null;
break;
case 1:
// TODO: implement DeviceGray
break;
case 3:
data.color = color;
break;
case 4:
// TODO: implement DeviceCMYK
break;
}
}
this.setColor(dict.get('C'));
data.color = this.color;

this.borderStyle = data.borderStyle = new AnnotationBorderStyle();
this.setBorderStyle(dict);
Expand All @@ -111,6 +91,48 @@ var Annotation = (function AnnotationClosure() {
}

Annotation.prototype = {
/**
* Set the color and take care of color space conversion.
*
* @public
* @memberof Annotation
* @param {Array} color - The color array containing either 0
* (transparent), 1 (grayscale), 3 (RGB) or
* 4 (CMYK) elements
*/
setColor: function Annotation_setColor(color) {
var rgbColor = new Uint8Array(3); // Black in RGB color space (default)
if (!isArray(color)) {
this.color = rgbColor;
return;
}

switch (color.length) {
case 0: // Transparent, which we indicate with a null value
this.color = null;
break;

case 1: // Convert grayscale to RGB
ColorSpace.singletons.gray.getRgbItem(color, 0, rgbColor, 0);
this.color = rgbColor;
break;

case 3: // Convert RGB percentages to RGB
ColorSpace.singletons.rgb.getRgbItem(color, 0, rgbColor, 0);
this.color = rgbColor;
break;

case 4: // Convert CMYK to RGB
ColorSpace.singletons.cmyk.getRgbItem(color, 0, rgbColor, 0);
this.color = rgbColor;
break;

default:
this.color = rgbColor;
break;
}
},

/**
* Set the border style (as AnnotationBorderStyle object).
*
Expand Down
22 changes: 10 additions & 12 deletions src/display/annotation_helper.js
Expand Up @@ -100,12 +100,12 @@ var AnnotationUtils = (function AnnotationUtilsClosure() {
// Border color
if (item.color) {
container.style.borderColor =
Util.makeCssRgb(Math.round(item.color[0] * 255),
Math.round(item.color[1] * 255),
Math.round(item.color[2] * 255));
Util.makeCssRgb(item.color[0] | 0,
item.color[1] | 0,
item.color[2] | 0);
} else {
// Default color is black, but that's not obvious from the spec.
container.style.borderColor = 'rgb(0,0,0)';
// Transparent (invisible) border, so do not draw it at all.
container.style.borderWidth = 0;
}
}

Expand Down Expand Up @@ -172,17 +172,15 @@ var AnnotationUtils = (function AnnotationUtilsClosure() {
content.setAttribute('hidden', true);

var i, ii;
if (item.hasBgColor) {
if (item.hasBgColor && item.color) {
var color = item.color;

// Enlighten the color (70%)
var BACKGROUND_ENLIGHT = 0.7;
var r = BACKGROUND_ENLIGHT * (1.0 - color[0]) + color[0];
var g = BACKGROUND_ENLIGHT * (1.0 - color[1]) + color[1];
var b = BACKGROUND_ENLIGHT * (1.0 - color[2]) + color[2];
content.style.backgroundColor = Util.makeCssRgb((r * 255) | 0,
(g * 255) | 0,
(b * 255) | 0);
var r = BACKGROUND_ENLIGHT * (255 - color[0]) + color[0];
var g = BACKGROUND_ENLIGHT * (255 - color[1]) + color[1];
var b = BACKGROUND_ENLIGHT * (255 - color[2]) + color[2];
content.style.backgroundColor = Util.makeCssRgb(r | 0, g | 0, b | 0);
}

var title = document.createElement('h1');
Expand Down
58 changes: 57 additions & 1 deletion test/unit/annotation_layer_spec.js
@@ -1,11 +1,67 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* globals expect, it, describe, Dict, AnnotationBorderStyle,
/* globals expect, it, describe, Dict, Annotation, AnnotationBorderStyle,
AnnotationBorderStyleType */

'use strict';

describe('Annotation layer', function() {
describe('Annotation', function() {
it('should reject a color if it is not an array', function() {
var dict = new Dict();
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor('red');

expect(annotation.color).toEqual([0, 0, 0]);
});

it('should set and get a transparent color', function() {
var dict = new Dict();
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor([]);

expect(annotation.color).toEqual(null);
});

it('should set and get a grayscale color', function() {
var dict = new Dict();
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor([0.4]);

expect(annotation.color).toEqual([102, 102, 102]);
});

it('should set and get an RGB color', function() {
var dict = new Dict();
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor([0, 0, 1]);

expect(annotation.color).toEqual([0, 0, 255]);
});

it('should set and get a CMYK color', function() {
var dict = new Dict();
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor([0.1, 0.92, 0.84, 0.02]);

expect(annotation.color).toEqual([233, 59, 47]);
});

it('should not set and get an invalid color', function() {
var dict = new Dict();
dict.set('Subtype', '');
var annotation = new Annotation({ dict: dict, ref: 0 });
annotation.setColor([0.4, 0.6]);

expect(annotation.color).toEqual([0, 0, 0]);
});
});

describe('AnnotationBorderStyle', function() {
it('should set and get a valid width', function() {
var borderStyle = new AnnotationBorderStyle();
Expand Down