@vibrant/image
Advanced tools
Comparing version 4.0.0-alpha.3 to 4.0.0-alpha.4
import { Callback } from '@vibrant/types'; | ||
import { Filter } from '@vibrant/color'; | ||
/// <reference types="node" /> | ||
/// <reference types="node" /> | ||
export { Histogram } from './histogram.js'; | ||
@@ -6,0 +5,0 @@ export type { HistogramOptions } from './histogram.js'; |
@@ -17,2 +17,3 @@ import { Histogram } from "./histogram.js"; | ||
function applyFilters(imageData, filters) { | ||
var _a; | ||
if (filters.length > 0) { | ||
@@ -33,3 +34,3 @@ const pixels = imageData.data; | ||
for (let j = 0; j < filters.length; j++) { | ||
if (!filters[j](r, g, b, a)) { | ||
if (!((_a = filters[j]) == null ? void 0 : _a.call(filters, r, g, b, a))) { | ||
pixels[offset + 3] = 0; | ||
@@ -36,0 +37,0 @@ break; |
103
package.json
{ | ||
"name": "@vibrant/image", | ||
"version": "4.0.0-alpha.3", | ||
"description": "Helpers and typings for writing a vibrant ImageClass", | ||
"scripts": { | ||
"build": "vite build" | ||
}, | ||
"type": "module", | ||
"types": "dist/esm/index.d.ts", | ||
"main": "dist/cjs/index.cjs", | ||
"module": "dist/esm/index.js", | ||
"exports": { | ||
".": { | ||
"import": { | ||
"types": "./dist/esm/index.d.ts", | ||
"default": "./dist/esm/index.js" | ||
}, | ||
"require": { | ||
"types": "./dist/cjs/index.d.cts", | ||
"default": "./dist/cjs/index.cjs" | ||
} | ||
}, | ||
"./package.json": "./package.json" | ||
}, | ||
"sideEffects": false, | ||
"files": [ | ||
"dist", | ||
"src" | ||
], | ||
"author": { | ||
"name": "akfish", | ||
"email": "akfish@gmail.com" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/akfish/node-vibrant/issues" | ||
}, | ||
"homepage": "https://github.com/akfish/node-vibrant", | ||
"license": "MIT", | ||
"dependencies": { | ||
"@vibrant/color": "^4.0.0-alpha.3", | ||
"@vibrant/types": "^4.0.0-alpha.3" | ||
}, | ||
"devDependencies": { | ||
"@tanstack/config": "^0.14.2", | ||
"@types/node": "^18.15.3", | ||
"typescript": "^4.5.2", | ||
"vite": "^6.0.3" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"gitHead": "2cdb48edcf5398024bd18a6ed07f2ec50a20030b" | ||
"name": "@vibrant/image", | ||
"version": "4.0.0-alpha.4", | ||
"description": "Helpers and typings for writing a vibrant ImageClass", | ||
"scripts": { | ||
"build": "vite build", | ||
"test:eslint": "eslint ./src" | ||
}, | ||
"type": "module", | ||
"types": "dist/esm/index.d.ts", | ||
"main": "dist/cjs/index.cjs", | ||
"module": "dist/esm/index.js", | ||
"exports": { | ||
".": { | ||
"import": { | ||
"types": "./dist/esm/index.d.ts", | ||
"default": "./dist/esm/index.js" | ||
}, | ||
"require": { | ||
"types": "./dist/cjs/index.d.cts", | ||
"default": "./dist/cjs/index.cjs" | ||
} | ||
}, | ||
"./package.json": "./package.json" | ||
}, | ||
"sideEffects": false, | ||
"files": [ | ||
"dist", | ||
"src" | ||
], | ||
"author": { | ||
"name": "akfish", | ||
"email": "akfish@gmail.com" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/akfish/node-vibrant/issues" | ||
}, | ||
"homepage": "https://github.com/akfish/node-vibrant", | ||
"license": "MIT", | ||
"dependencies": { | ||
"@vibrant/color": "^4.0.0-alpha.4", | ||
"@vibrant/types": "^4.0.0-alpha.4" | ||
}, | ||
"devDependencies": { | ||
"@tanstack/config": "^0.14.2", | ||
"@types/node": "^18.15.3", | ||
"typescript": "^4.5.2", | ||
"vite": "^6.0.3" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"gitHead": "87c300667e339a8bc4f463d058c0e960f8d18ba9" | ||
} |
# @vibrant/image | ||
Helpers and typings for writing a vibrant ImageClass | ||
@@ -1,82 +0,85 @@ | ||
import { Pixels } from "./index"; | ||
import type { Pixels } from "./index"; | ||
export interface HistogramOptions { | ||
sigBits: number; | ||
sigBits: number; | ||
} | ||
export class Histogram { | ||
bmin: number; | ||
bmax: number; | ||
gmin: number; | ||
gmax: number; | ||
rmin: number; | ||
rmax: number; | ||
hist: Uint32Array; | ||
private _colorCount: number; | ||
get colorCount() { | ||
return this._colorCount; | ||
} | ||
getColorIndex: (r: number, g: number, b: number) => number; | ||
constructor(public pixels: Pixels, public opts: HistogramOptions) { | ||
const { sigBits } = opts; | ||
const getColorIndex = (r: number, g: number, b: number) => | ||
(r << (2 * sigBits)) + (g << sigBits) + b; | ||
bmin: number; | ||
bmax: number; | ||
gmin: number; | ||
gmax: number; | ||
rmin: number; | ||
rmax: number; | ||
hist: Uint32Array; | ||
private _colorCount: number; | ||
get colorCount() { | ||
return this._colorCount; | ||
} | ||
getColorIndex: (r: number, g: number, b: number) => number; | ||
constructor( | ||
public pixels: Pixels, | ||
public opts: HistogramOptions, | ||
) { | ||
const { sigBits } = opts; | ||
const getColorIndex = (r: number, g: number, b: number) => | ||
(r << (2 * sigBits)) + (g << sigBits) + b; | ||
this.getColorIndex = getColorIndex; | ||
this.getColorIndex = getColorIndex; | ||
const rshift = 8 - sigBits; | ||
const hn = 1 << (3 * sigBits); | ||
const hist = new Uint32Array(hn); | ||
let rmax: number; | ||
let rmin: number; | ||
let gmax: number; | ||
let gmin: number; | ||
let bmax: number; | ||
let bmin: number; | ||
let r: number; | ||
let g: number; | ||
let b: number; | ||
let a: number; | ||
rmax = gmax = bmax = 0; | ||
rmin = gmin = bmin = Number.MAX_VALUE; | ||
const n = pixels.length / 4; | ||
let i = 0; | ||
const rshift = 8 - sigBits; | ||
const hn = 1 << (3 * sigBits); | ||
const hist = new Uint32Array(hn); | ||
let rmax: number; | ||
let rmin: number; | ||
let gmax: number; | ||
let gmin: number; | ||
let bmax: number; | ||
let bmin: number; | ||
let r: number; | ||
let g: number; | ||
let b: number; | ||
let a: number; | ||
rmax = gmax = bmax = 0; | ||
rmin = gmin = bmin = Number.MAX_VALUE; | ||
const n = pixels.length / 4; | ||
let i = 0; | ||
while (i < n) { | ||
const offset = i * 4; | ||
i++; | ||
r = pixels[offset + 0]; | ||
g = pixels[offset + 1]; | ||
b = pixels[offset + 2]; | ||
a = pixels[offset + 3]; | ||
while (i < n) { | ||
const offset = i * 4; | ||
i++; | ||
r = pixels[offset + 0]!; | ||
g = pixels[offset + 1]!; | ||
b = pixels[offset + 2]!; | ||
a = pixels[offset + 3]!; | ||
// Ignored pixels' alpha is marked as 0 in filtering stage | ||
if (a === 0) continue; | ||
// Ignored pixels' alpha is marked as 0 in filtering stage | ||
if (a === 0) continue; | ||
r = r >> rshift; | ||
g = g >> rshift; | ||
b = b >> rshift; | ||
r = r >> rshift; | ||
g = g >> rshift; | ||
b = b >> rshift; | ||
const index = getColorIndex(r, g, b); | ||
hist[index] += 1; | ||
const index = getColorIndex(r, g, b); | ||
hist[index] += 1; | ||
if (r > rmax) rmax = r; | ||
if (r < rmin) rmin = r; | ||
if (g > gmax) gmax = g; | ||
if (g < gmin) gmin = g; | ||
if (b > bmax) bmax = b; | ||
if (b < bmin) bmin = b; | ||
} | ||
this._colorCount = hist.reduce( | ||
(total, c) => (c > 0 ? total + 1 : total), | ||
0 | ||
); | ||
this.hist = hist; | ||
this.rmax = rmax; | ||
this.rmin = rmin; | ||
this.gmax = gmax; | ||
this.gmin = gmin; | ||
this.bmax = bmax; | ||
this.bmin = bmin; | ||
} | ||
if (r > rmax) rmax = r; | ||
if (r < rmin) rmin = r; | ||
if (g > gmax) gmax = g; | ||
if (g < gmin) gmin = g; | ||
if (b > bmax) bmax = b; | ||
if (b < bmin) bmin = b; | ||
} | ||
this._colorCount = hist.reduce( | ||
(total, c) => (c > 0 ? total + 1 : total), | ||
0, | ||
); | ||
this.hist = hist; | ||
this.rmax = rmax; | ||
this.rmin = rmin; | ||
this.gmax = gmax; | ||
this.gmin = gmin; | ||
this.bmax = bmax; | ||
this.bmin = bmin; | ||
} | ||
} |
135
src/index.ts
@@ -0,5 +1,6 @@ | ||
import type { Callback } from "@vibrant/types"; | ||
import type { Filter } from "@vibrant/color"; | ||
export { Histogram } from "./histogram"; | ||
export type { HistogramOptions } from "./histogram"; | ||
import { Callback } from "@vibrant/types"; | ||
import { Filter } from "@vibrant/color"; | ||
@@ -12,87 +13,87 @@ export type ImageCallback = Callback<Image>; | ||
export interface ImageData { | ||
data: Pixels; | ||
width: number; | ||
height: number; | ||
data: Pixels; | ||
width: number; | ||
height: number; | ||
} | ||
export interface ImageOptions { | ||
quality: number; | ||
maxDimension: number; | ||
quality: number; | ||
maxDimension: number; | ||
} | ||
export interface Image { | ||
load(image: ImageSource): Promise<Image>; | ||
clear(): void; | ||
update(imageData: ImageData): void; | ||
getWidth(): number; | ||
getHeight(): number; | ||
resize(targetWidth: number, targetHeight: number, ratio: number): void; | ||
getPixelCount(): number; | ||
getImageData(): ImageData; | ||
remove(): void; | ||
scaleDown(opts: ImageOptions): void; | ||
load(image: ImageSource): Promise<Image>; | ||
clear(): void; | ||
update(imageData: ImageData): void; | ||
getWidth(): number; | ||
getHeight(): number; | ||
resize(targetWidth: number, targetHeight: number, ratio: number): void; | ||
getPixelCount(): number; | ||
getImageData(): ImageData; | ||
remove(): void; | ||
scaleDown(opts: ImageOptions): void; | ||
} | ||
export interface ImageClass { | ||
new (): Image; | ||
new (): Image; | ||
} | ||
export abstract class ImageBase implements Image { | ||
abstract load(image: ImageSource): Promise<ImageBase>; | ||
abstract clear(): void; | ||
abstract update(imageData: ImageData): void; | ||
abstract getWidth(): number; | ||
abstract getHeight(): number; | ||
abstract resize( | ||
targetWidth: number, | ||
targetHeight: number, | ||
ratio: number | ||
): void; | ||
abstract getPixelCount(): number; | ||
abstract getImageData(): ImageData; | ||
abstract remove(): void; | ||
abstract load(image: ImageSource): Promise<ImageBase>; | ||
abstract clear(): void; | ||
abstract update(imageData: ImageData): void; | ||
abstract getWidth(): number; | ||
abstract getHeight(): number; | ||
abstract resize( | ||
targetWidth: number, | ||
targetHeight: number, | ||
ratio: number, | ||
): void; | ||
abstract getPixelCount(): number; | ||
abstract getImageData(): ImageData; | ||
abstract remove(): void; | ||
scaleDown(opts: ImageOptions): void { | ||
const width: number = this.getWidth(); | ||
const height: number = this.getHeight(); | ||
scaleDown(opts: ImageOptions): void { | ||
const width: number = this.getWidth(); | ||
const height: number = this.getHeight(); | ||
let ratio = 1; | ||
let ratio = 1; | ||
if (opts.maxDimension > 0) { | ||
const maxSide: number = Math.max(width, height); | ||
if (maxSide > opts.maxDimension) ratio = opts.maxDimension / maxSide; | ||
} else { | ||
ratio = 1 / opts.quality; | ||
} | ||
if (opts.maxDimension > 0) { | ||
const maxSide: number = Math.max(width, height); | ||
if (maxSide > opts.maxDimension) ratio = opts.maxDimension / maxSide; | ||
} else { | ||
ratio = 1 / opts.quality; | ||
} | ||
if (ratio < 1) this.resize(width * ratio, height * ratio, ratio); | ||
} | ||
if (ratio < 1) this.resize(width * ratio, height * ratio, ratio); | ||
} | ||
} | ||
export function applyFilters(imageData: ImageData, filters: Filter[]) { | ||
if (filters.length > 0) { | ||
const pixels = imageData.data; | ||
const n = pixels.length / 4; | ||
let offset; | ||
let r; | ||
let g; | ||
let b; | ||
let a; | ||
for (let i = 0; i < n; i++) { | ||
offset = i * 4; | ||
r = pixels[offset + 0]; | ||
g = pixels[offset + 1]; | ||
b = pixels[offset + 2]; | ||
a = pixels[offset + 3]; | ||
// Mark ignored color | ||
for (let j = 0; j < filters.length; j++) { | ||
if (!filters[j](r, g, b, a)) { | ||
pixels[offset + 3] = 0; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
if (filters.length > 0) { | ||
const pixels = imageData.data; | ||
const n = pixels.length / 4; | ||
let offset; | ||
let r; | ||
let g; | ||
let b; | ||
let a; | ||
for (let i = 0; i < n; i++) { | ||
offset = i * 4; | ||
r = pixels[offset + 0]!; | ||
g = pixels[offset + 1]!; | ||
b = pixels[offset + 2]!; | ||
a = pixels[offset + 3]!; | ||
// Mark ignored color | ||
for (let j = 0; j < filters.length; j++) { | ||
if (!filters[j]?.(r, g, b, a)) { | ||
pixels[offset + 3] = 0; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
return imageData; | ||
return imageData; | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
445
28662
4