Skip to content

Commit

Permalink
Added Flow typing
Browse files Browse the repository at this point in the history
  • Loading branch information
gforge committed Dec 26, 2017
1 parent a2e8db4 commit e34c1c3
Show file tree
Hide file tree
Showing 8 changed files with 327 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"presets": ["env"],
"presets": ["env", "flow"],
"env": {
"test": {
"plugins": ["istanbul"]
Expand Down
5 changes: 5 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
{
"plugins": ["flowtype"],
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 8,
"sourceType": "module"
},
"extends": [
"plugin:flowtype/recommended"
],
"rules": {
"no-alert": 2,
"no-array-constructor": 0,
Expand Down
12 changes: 12 additions & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[ignore]

[include]

[libs]
flow-typed

[lints]

[options]

[strict]
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ node_modules
coverage
examples/*.png
browser\.js
browser\.js\.flow
dist
package-lock\.json
\.nyc_output
flow-typed/npm
13 changes: 13 additions & 0 deletions flow-typed/pngjs-types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// @flow

declare type Metadata = {|
width: number,
height: number,
depth: 1 | 2 | 4 | 8 | 16,
interlace: boolean,
palette: boolean,
color: boolean,
alpha: boolean,
bpp: 1 | 2 | 3 | 4,
colorType: 0 | 2 | 3 | 4 | 6,
|}
103 changes: 72 additions & 31 deletions lib/png.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
import Stream from 'stream';
// @flow
import Stream, { type Readable, type Writable } from 'stream';
import { ParserAsync as Parser } from './parser';
import { PackerAsync as Packer } from './packer';
import * as PNGSync from './png-sync';
import * as propData from './propData';

type Props = {
width?: number,
height?: number,
initGrayscaleData?: boolean,
initPropData?: boolean | { shrinkMax: boolean, shrinkMin: boolean },
}

// $FlowFixMe
export class PNG extends Stream {
constructor(options) {
width: number;
height: number;
color: boolean;
depth: number;
_grayscaleData: Uint8Array | Uint16Array | void;
_propData: ?Float32Array;
data: ?Buffer;
gamma: number;

constructor(options: Props = {}) {
super(options);
Stream.call(this);

options = options || {}; // eslint-disable-line no-param-reassign
const {
width, height,
initGrayscaleData, initPropData,
} = options;

// coerce pixel dimensions to integers (also coerces undefined -> 0):
this.width = options.width | 0;
this.height = options.height | 0;
this.width = width || 0;
this.height = height || 0;

this.color = undefined;
this.depth = undefined;
this._grayscaleData = undefined;
this._propData = undefined;
this._configPostParse = {
initGrayscaleData: options.initGrayscaleData,
initPropData: options.initPropData,
};
this._configPostParse = { initGrayscaleData, initPropData };

this.data = this.width > 0 && this.height > 0 ?
new Buffer(4 * this.width * this.height) : null;
Expand Down Expand Up @@ -56,6 +68,7 @@ export class PNG extends Stream {
this._postParsed = this._postParsed.bind(this);
}

_postParsed: Function;
_postParsed() {
this._grayscaleData = undefined;
this._propData = undefined;
Expand Down Expand Up @@ -83,7 +96,7 @@ export class PNG extends Stream {
return this;
}

parse(data, callback) {
parse(data: ArrayBuffer | Readable, callback: Function) {
if (callback) {
let onParsed, onError;

Expand All @@ -107,16 +120,16 @@ export class PNG extends Stream {
return this;
}

write(data) {
write(data: Writable) {
this._parser.write(data);
return true;
}

end(data) {
end(data: Readable | ArrayBuffer) {
this._parser.end(data);
}

_metadata(metadata) {
_metadata(metadata: Metadata) {
const { width, height, color, depth } = metadata;
this.width = width;
this.height = height;
Expand All @@ -126,7 +139,7 @@ export class PNG extends Stream {
this.emit('metadata', metadata);
}

_gamma(gamma) {
_gamma(gamma: number) {
this.gamma = gamma;
}

Expand All @@ -136,7 +149,13 @@ export class PNG extends Stream {
}
}

bitblt(src, dst, srcX = 0, srcY = 0, width = 0, height = 0, deltaX = 0, deltaY = 0) { // eslint-disable-line max-params
// eslint-disable-next-line max-params
bitblt(
src: PNG, dst: PNG,
srcX: number = 0, srcY: number = 0,
width: number = 0, height: number = 0,
deltaX: number = 0, deltaY: number = 0,
) {
// coerce pixel dimensions to integers (also coerces undefined -> 0):

if (srcX > src.width || srcY > src.height || srcX + width > src.width || srcY + height > src.height) {
Expand All @@ -147,8 +166,17 @@ export class PNG extends Stream {
throw new Error('bitblt writing outside image');
}

const { data } = src;
if (!data) {
throw new Error('No data available in src');
}
const { data: outData } = dst;
if (!outData) {
throw new Error('No data available in dst');
}

for (var y = 0; y < height; y++) {
src.data.copy(dst.data,
data.copy(outData,
((deltaY + y) * dst.width + deltaX) << 2,
((srcY + y) * src.width + srcX) << 2,
((srcY + y) * src.width + srcX + width) << 2
Expand All @@ -158,41 +186,54 @@ export class PNG extends Stream {
return this;
}

adjustGamma(src) {
adjustGamma(src: PNG) {
if (src.gamma) {
const { data } = src;
if (!data) {
throw new Error('No data available for object');
}

for (var y = 0; y < src.height; y++) {
for (var x = 0; x < src.width; x++) {
var idx = (src.width * y + x) << 2;

for (var i = 0; i < 3; i++) {
var sample = src.data[idx + i] / 255;
var sample = data[idx + i] / 255;
sample = Math.pow(sample, 1 / 2.2 / src.gamma);
src.data[idx + i] = Math.round(sample * 255);
data[idx + i] = Math.round(sample * 255);
}
}
}
src.data = data;
src.gamma = 0;
}
return this;
}

initGrayscaleData() {
const { data } = this;
if (!data) {
throw new Error('The initGrayscaleData() called before receiving data');
}

let outData;
if (this.color) {
const mono = ({ red, green, blue }) => ((0.2125 * red) + (0.7154 * green) + (0.0721 * blue));
this._grayscaleData = data.slice(data.length / 4);
for (let i = 0; i < this._grayscaleData.length; i += 1) {
outData = data.slice(data.length / 4);
for (let i = 0; i < outData.length; i += 1) {
const pxPos = i * 4;
this._grayscaleData[i] = mono({
outData[i] = mono({
red: data[pxPos + 0],
green: data[pxPos + 1],
blue: data[pxPos + 2],
});
}
}
else {
this._grayscaleData = data.filter((clr, i) => i % 4 === 0);
outData = data.filter((clr, i) => i % 4 === 0);
}

this._grayscaleData = outData;
}

// Retrieve mono data without aplpha channel
Expand All @@ -209,7 +250,7 @@ export class PNG extends Stream {
return this._grayscaleData;
}

initPropData(shrinkMin = false, shrinkMax = false) {
initPropData(shrinkMin: boolean = false, shrinkMax: boolean = false) {
if (this.color) {
this._propData = propData.color(
this.data,
Expand Down Expand Up @@ -239,7 +280,7 @@ export class PNG extends Stream {
// Retrieve colors as proportions instead of integers
// if you want to limit the max proporiton to the bufferEqual
// max/min value then set the shrinkMax/shrinkMin.
propData(shrinkMin = false, shrinkMax = false) {
propData(shrinkMin: boolean = false, shrinkMax: boolean = false) {
const { data } = this;
if (!data) {
throw new Error('Invalid call - no data to convert');
Expand Down
14 changes: 10 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,12 @@
"test": "test"
},
"scripts": {
"build": "npm run compile && npm run browserify",
"build": "npm run compile && npm run build:flow && npm run build:browserify",
"build:flow": "flow-copy-source -v -i 'test/**' lib dist",
"build:clean": "rimraf dist",
"build:browserify": "browserify dist/png.js --standalone png > browser.js && cp dist/png.js.flow browser.js.flow",
"prepublish": "npm run build",
"clean:dist": "rimraf dist",
"compile": "npm run clean:dist && babel -d dist/ lib/",
"browserify": "browserify dist/png.js --standalone png > browser.js",
"compile": "npm run build:clean && babel -d dist/ lib/",
"coverage": "NODE_ENV=test nyc babel-tape-runner test/*-spec.js nolarge| tap-nyc",
"coveralls": "nyc report --reporter=text-lcov | coveralls",
"monitor": "nodemon --watch lib --delay 2.5s --exec \"npm run build\"",
Expand All @@ -67,15 +68,20 @@
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-eslint": "^8.1.2",
"babel-plugin-istanbul": "^4.1.5",
"babel-preset-env": "^1.6.1",
"babel-preset-flow": "^6.23.0",
"babel-register": "^6.26.0",
"babel-tape-runner": "^2.0.1",
"browserify": "^14.5.0",
"buffer-equal": "1.0.0",
"connect": "^3.6.5",
"coveralls": "^3.0.0",
"eslint": "^4.14.0",
"eslint-plugin-flowtype": "^2.40.1",
"flow-bin": "^0.61.0",
"flow-copy-source": "^1.2.1",
"istanbul": "^0.4.4",
"nodemon": "^1.14.3",
"nyc": "^11.4.1",
Expand Down
Loading

0 comments on commit e34c1c3

Please sign in to comment.