nautical-charts
Advanced tools
Comparing version 0.1.0 to 0.2.0
@@ -1,10 +0,28 @@ | ||
import { KapMetadata } from './metadata'; | ||
import { KapRasterRow } from './raster'; | ||
import { KapTextEntry } from './text'; | ||
export { KapRasterRow, KapRasterRun, writeRasterSegment } from './raster'; | ||
export interface KapChart { | ||
readonly metadata?: KapMetadata; | ||
readonly rasterSegment?: KapRasterRow[]; | ||
readonly textSegment?: KapTextEntry[]; | ||
/// <reference types="node" /> | ||
import { BsbRasterRow } from './raster'; | ||
import { BsbTextEntry } from './text'; | ||
export { MemoryStream } from './memoryStream'; | ||
export { BsbMetadata, parseMetadata } from './metadata'; | ||
export { BsbRasterRow, BsbRasterRun, writeRasterSegment } from './raster'; | ||
/** | ||
* @module nautical-charts | ||
*/ | ||
/** | ||
* A BSB chart. | ||
*/ | ||
export interface BsbChart { | ||
/** | ||
* The rows that comprise the raster segment of the chart. | ||
*/ | ||
readonly rasterSegment?: BsbRasterRow[]; | ||
/** | ||
* The text entries that comprise the text segment of the chart. | ||
*/ | ||
readonly textSegment?: BsbTextEntry[]; | ||
} | ||
export declare function readChart(contents: Uint8Array): KapChart | undefined; | ||
/** | ||
* Parses a BSB chart from a readable (e.g. file) stream. | ||
* @param stream The stream from which to read the chart data. | ||
* @returns A BSB chart. | ||
*/ | ||
export declare function parseChart(stream: NodeJS.ReadableStream): Promise<BsbChart>; |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
// Copyright (c) Phillip Hoff <phillip@orst.edu>. | ||
// Licensed under the MIT license. | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.readChart = exports.writeRasterSegment = void 0; | ||
const util_1 = require("util"); | ||
const metadata_1 = require("./metadata"); | ||
exports.parseChart = exports.writeRasterSegment = exports.parseMetadata = exports.MemoryStream = void 0; | ||
const chartStream_1 = require("./chartStream"); | ||
const raster_1 = require("./raster"); | ||
const stream_1 = __importDefault(require("./stream")); | ||
const text_1 = require("./text"); | ||
var memoryStream_1 = require("./memoryStream"); | ||
Object.defineProperty(exports, "MemoryStream", { enumerable: true, get: function () { return memoryStream_1.MemoryStream; } }); | ||
var metadata_1 = require("./metadata"); | ||
Object.defineProperty(exports, "parseMetadata", { enumerable: true, get: function () { return metadata_1.parseMetadata; } }); | ||
var raster_2 = require("./raster"); | ||
Object.defineProperty(exports, "writeRasterSegment", { enumerable: true, get: function () { return raster_2.writeRasterSegment; } }); | ||
const decoder = new util_1.TextDecoder(); | ||
function readChart(contents) { | ||
const stream = new stream_1.default(contents); | ||
const textSegmentEndToken = [0x1A, 0x00]; | ||
const textSegmentBuffer = stream.readUntil(textSegmentEndToken, { consumeValues: true }); | ||
let textSegment; | ||
if (textSegmentBuffer) { | ||
const textSection = decoder.decode(textSegmentBuffer); | ||
textSegment = text_1.parseTextSegment(textSection); | ||
} | ||
let metadata; | ||
if (textSegment) { | ||
metadata = metadata_1.parseMetadata(textSegment); | ||
} | ||
let rasterSegment; | ||
// TODO: Verify match to text section. | ||
const bitDepth = stream.next(); | ||
if (bitDepth !== undefined) { | ||
rasterSegment = raster_1.parseRasterSegment(stream, bitDepth); | ||
} | ||
return { metadata, textSegment, rasterSegment }; | ||
/** | ||
* Parses a BSB chart from a readable (e.g. file) stream. | ||
* @param stream The stream from which to read the chart data. | ||
* @returns A BSB chart. | ||
*/ | ||
function parseChart(stream) { | ||
return new Promise((resolve, reject) => { | ||
const textEntries = []; | ||
let bitDepth; | ||
const rows = []; | ||
const chartStream = new chartStream_1.ChartStream({ objectMode: true }); | ||
stream.pipe(chartStream); | ||
chartStream.on('data', (data) => { | ||
switch (data.type) { | ||
case 'text': | ||
textEntries.push(data.text); | ||
break; | ||
case 'bitDepth': | ||
bitDepth = data.bitDepth; | ||
break; | ||
case 'row': | ||
rows.push(data.row); | ||
break; | ||
} | ||
}); | ||
chartStream.on('end', () => { | ||
const textSegment = text_1.parseTextSegmentEntries(textEntries); | ||
const rasterSegment = raster_1.parseRasterSegment(rows, bitDepth); | ||
resolve({ | ||
rasterSegment, | ||
textSegment | ||
}); | ||
}); | ||
chartStream.on('error', err => { | ||
reject(err); | ||
}); | ||
}); | ||
} | ||
exports.readChart = readChart; | ||
exports.parseChart = parseChart; | ||
//# sourceMappingURL=index.js.map |
@@ -1,4 +0,11 @@ | ||
import { KapTextEntry } from "./text"; | ||
export interface KapPalette { | ||
[index: number]: { | ||
import { BsbTextEntry } from "./text"; | ||
/** | ||
* A palette for a BSB chart. | ||
*/ | ||
export interface BsbPalette { | ||
/** | ||
* @param index The (1-based) index of a color within the palette. | ||
* @returns A color in RGBA notation. | ||
*/ | ||
readonly [index: number]: { | ||
r: number; | ||
@@ -10,7 +17,34 @@ g: number; | ||
} | ||
export interface KapMetadata { | ||
/** | ||
* The size of the BSB chart. | ||
*/ | ||
export interface BsbSize { | ||
/** | ||
* The height (in pixels) of the raster data of the chart. | ||
*/ | ||
readonly height?: number; | ||
readonly palette?: KapPalette; | ||
/** | ||
* The width (in pixels) of the raster data of the chart. | ||
*/ | ||
readonly width?: number; | ||
} | ||
export declare function parseMetadata(textSegment: KapTextEntry[]): KapMetadata; | ||
/** | ||
* Metadata related to a BSB chart, as parsed from its text segment. | ||
*/ | ||
export interface BsbMetadata { | ||
/** | ||
* The primary palette of the chart. | ||
*/ | ||
readonly palette?: BsbPalette; | ||
/** | ||
* The size of the chart. | ||
*/ | ||
readonly size?: BsbSize; | ||
} | ||
export declare function parsePalette(entry: BsbTextEntry, metadata: BsbMetadata): BsbMetadata; | ||
/** | ||
* Parses the text segment of a BSB chart and returns well-known metadata, if present. | ||
* @param textSegment The text entries of the chart. | ||
* @returns The metadata parsed from the chart. | ||
*/ | ||
export declare function parseMetadata(textSegment: BsbTextEntry[]): BsbMetadata; |
"use strict"; | ||
// Copyright (c) Phillip Hoff <phillip@orst.edu>. | ||
// Licensed under the MIT license. | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.parseMetadata = void 0; | ||
function parseHeightAndWidth(textSegment) { | ||
const header = textSegment.find(entry => entry.entryType === 'BSB'); | ||
if (header) { | ||
const regex = /RA=(?<width>\d+),(?<height>\d+)/; | ||
for (let line of header.lines) { | ||
const match = regex.exec(line); | ||
if (match) { | ||
return { | ||
exports.parseMetadata = exports.parsePalette = void 0; | ||
function parseSize(entry, metadata) { | ||
const regex = /RA=(?<width>\d+),(?<height>\d+)/; | ||
for (let line of entry.lines) { | ||
const match = regex.exec(line); | ||
if (match) { | ||
return { | ||
...metadata, | ||
size: { | ||
height: parseInt(match.groups['height'], 10), | ||
width: parseInt(match.groups['width'], 10) | ||
}; | ||
} | ||
} | ||
}; | ||
} | ||
} | ||
return {}; | ||
return metadata; | ||
} | ||
function parsePalette(entry, metadata) { | ||
const regex = /^(?<index>\d+),(?<r>\d+),(?<g>\d+),(?<b>\d+)$/; | ||
const match = regex.exec(entry.lines[0]); | ||
if (match) { | ||
const index = parseInt(match.groups['index'], 10); | ||
const r = parseInt(match.groups['r'], 10); | ||
const g = parseInt(match.groups['g'], 10); | ||
const b = parseInt(match.groups['b'], 10); | ||
return { | ||
...metadata, | ||
palette: { | ||
...metadata.palette, | ||
[index]: { r, g, b } | ||
} | ||
}; | ||
} | ||
return metadata; | ||
} | ||
exports.parsePalette = parsePalette; | ||
const typeParsers = { | ||
BSB: parseSize, | ||
RGB: parsePalette | ||
}; | ||
/** | ||
* Parses the text segment of a BSB chart and returns well-known metadata, if present. | ||
* @param textSegment The text entries of the chart. | ||
* @returns The metadata parsed from the chart. | ||
*/ | ||
function parseMetadata(textSegment) { | ||
const palette = {}; | ||
for (let rgbEntry of textSegment.filter(entry => entry.entryType === 'RGB')) { | ||
const regex = /^(?<index>\d+),(?<r>\d+),(?<g>\d+),(?<b>\d+)$/; | ||
const match = regex.exec(rgbEntry.lines[0]); | ||
if (match) { | ||
const index = parseInt(match.groups['index'], 10); | ||
const r = parseInt(match.groups['r'], 10); | ||
const g = parseInt(match.groups['g'], 10); | ||
const b = parseInt(match.groups['b'], 10); | ||
palette[index] = { r, g, b }; | ||
let metadata = {}; | ||
for (let entry of textSegment) { | ||
const parser = typeParsers[entry.entryType]; | ||
if (parser) { | ||
metadata = parser(entry, metadata); | ||
} | ||
} | ||
const { height, width } = parseHeightAndWidth(textSegment); | ||
return { | ||
height, | ||
palette, | ||
width | ||
}; | ||
return metadata; | ||
} | ||
exports.parseMetadata = parseMetadata; | ||
//# sourceMappingURL=metadata.js.map |
/// <reference types="node" /> | ||
import { KapPalette } from "./metadata"; | ||
import KapStream from "./stream"; | ||
export interface KapRasterRun { | ||
colorIndex: number; | ||
length: number; | ||
import { BsbPalette } from "./metadata"; | ||
/** | ||
* A sequential series of pixels of the same color in a row of raster data. | ||
*/ | ||
export interface BsbRasterRun { | ||
/** | ||
* The index into a color palette that indicates the color of the pixels. | ||
*/ | ||
readonly colorIndex: number; | ||
/** The number of pixels in the run. */ | ||
readonly length: number; | ||
} | ||
export interface KapRasterRow { | ||
/** | ||
* A single row of raster data within the chart. | ||
*/ | ||
export interface BsbRasterRow { | ||
/** | ||
* The (1-based) number of the row. | ||
*/ | ||
readonly rowNumber: number; | ||
readonly runs: KapRasterRun[]; | ||
/** | ||
* The runs that encode the raster data of the row. | ||
*/ | ||
readonly runs: BsbRasterRun[]; | ||
} | ||
export declare function parseRasterSegment(stream: KapStream, bitDepth: number): KapRasterRow[]; | ||
export declare function writeRasterSegment(rasterSegment: KapRasterRow[], palette: KapPalette, buffer: Buffer, bufferWidth: number): void; | ||
export declare function parseRasterSegment(rows: number[][][], bitDepth: number): BsbRasterRow[]; | ||
/** | ||
* Writes the RLE encoded raster data of a BSB chart to a bitmap. | ||
* @param rasterSegment The rows of raster data for the chart. | ||
* @param palette The palette from which to obtain pixel values. | ||
* @param buffer The bitmap buffer in which to write the chart raster data. | ||
* @param bufferWidth The width of the bitmap buffer. | ||
*/ | ||
export declare function writeRasterSegment(rasterSegment: BsbRasterRow[], palette: BsbPalette, buffer: Buffer, bufferWidth: number): void; |
"use strict"; | ||
// Copyright (c) Phillip Hoff <phillip@orst.edu>. | ||
// Licensed under the MIT license. | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -24,15 +26,3 @@ exports.writeRasterSegment = exports.parseRasterSegment = void 0; | ||
]; | ||
function readVariableLengthValue(stream) { | ||
const row = []; | ||
let current; | ||
do { | ||
current = stream.next(); | ||
if (current !== undefined) { | ||
row.push(current & 0x7F); | ||
} | ||
} while (current !== undefined && current > 127); | ||
return row; | ||
} | ||
function readRowNumber(stream) { | ||
const value = readVariableLengthValue(stream); | ||
function readRowNumber(value) { | ||
let number = 0; | ||
@@ -44,5 +34,4 @@ for (let i = value.length - 1, pow = 0; i >= 0; i--, pow++) { | ||
} | ||
function readRasterRun(stream, bitDepth) { | ||
function readRasterRun(value, bitDepth) { | ||
let colorIndexMask = colorIndexMasks[bitDepth]; | ||
const value = readVariableLengthValue(stream); | ||
const colorIndex = (value[0] & colorIndexMask) >>> (7 - bitDepth); | ||
@@ -60,21 +49,14 @@ let lengthMask = runLengthMasks[bitDepth]; | ||
} | ||
function parseRasterSegment(stream, bitDepth) { | ||
const rows = []; | ||
// HACK: BSB 3.07 seems to omit the 4-null-byte token; it's probably generally be safe to | ||
// look for the 2-null-byte first half of the first index (which assumes the header | ||
// is less than 65KB). | ||
const rasterSegmentEndToken = [0x00, 0x00 /*, 0x00, 0x00 */]; | ||
while (stream.hasNext && !stream.isNext(rasterSegmentEndToken)) { | ||
const rowNumber = readRowNumber(stream); | ||
const runs = []; | ||
while (stream.hasNext && stream.peek(0) !== 0x00) { | ||
const value = readRasterRun(stream, bitDepth); | ||
runs.push(value); | ||
} | ||
stream.next(); | ||
rows.push({ rowNumber, runs }); | ||
} | ||
return rows; | ||
function parseRasterSegment(rows, bitDepth) { | ||
// TODO: Eliminate need for slice(). | ||
return rows.map(values => ({ rowNumber: readRowNumber(values[0]), runs: values.slice(1).map(value => readRasterRun(value, bitDepth)) })); | ||
} | ||
exports.parseRasterSegment = parseRasterSegment; | ||
/** | ||
* Writes the RLE encoded raster data of a BSB chart to a bitmap. | ||
* @param rasterSegment The rows of raster data for the chart. | ||
* @param palette The palette from which to obtain pixel values. | ||
* @param buffer The bitmap buffer in which to write the chart raster data. | ||
* @param bufferWidth The width of the bitmap buffer. | ||
*/ | ||
function writeRasterSegment(rasterSegment, palette, buffer, bufferWidth) { | ||
@@ -81,0 +63,0 @@ var _a, _b; |
"use strict"; | ||
// Copyright (c) Phillip Hoff <phillip@orst.edu>. | ||
// Licensed under the MIT license. | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -3,0 +5,0 @@ class KapStream { |
@@ -1,5 +0,15 @@ | ||
export interface KapTextEntry { | ||
entryType: string; | ||
lines: string[]; | ||
/** | ||
* A single entry within a BSB chart text segment, including all lines of text associated with the entry type. | ||
*/ | ||
export interface BsbTextEntry { | ||
/** | ||
* The type of this entry. | ||
*/ | ||
readonly entryType: string; | ||
/** | ||
* All lines of text associated with the entry type. | ||
*/ | ||
readonly lines: string[]; | ||
} | ||
export declare function parseTextSegment(textSegment: string): KapTextEntry[]; | ||
export declare function parseTextSegment(textSegment: string): BsbTextEntry[]; | ||
export declare function parseTextSegmentEntries(lines: string[]): BsbTextEntry[]; |
"use strict"; | ||
// Copyright (c) Phillip Hoff <phillip@orst.edu>. | ||
// Licensed under the MIT license. | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.parseTextSegment = void 0; | ||
exports.parseTextSegmentEntries = exports.parseTextSegment = void 0; | ||
function parseTextSegment(textSegment) { | ||
const lines = textSegment.split('\r\n'); | ||
return parseTextSegmentEntries(lines); | ||
} | ||
exports.parseTextSegment = parseTextSegment; | ||
function parseTextSegmentEntries(lines) { | ||
const entries = []; | ||
@@ -36,3 +42,3 @@ let currentEntry; | ||
} | ||
exports.parseTextSegment = parseTextSegment; | ||
exports.parseTextSegmentEntries = parseTextSegmentEntries; | ||
//# sourceMappingURL=text.js.map |
@@ -1,7 +0,5 @@ | ||
Nautical Charts Extension for Visual Studio Code | ||
MIT License | ||
Copyright (c) Phillip Hoff <phillip@orst.edu> | ||
Copyright (c) 2021 Phillip Hoff <phillip@orst.edu> | ||
MIT License | ||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
@@ -17,3 +15,3 @@ of this software and associated documentation files (the "Software"), to deal | ||
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
@@ -24,2 +22,2 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. | ||
SOFTWARE. |
{ | ||
"name": "nautical-charts", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "A library for reading nautical chart files.", | ||
@@ -15,10 +15,21 @@ "exports": { | ||
"scripts": { | ||
"build": "tsc" | ||
"build": "tsc", | ||
"docs": "jsdoc2md -t README.template.md dist/*.js > README.md", | ||
"test": "jest --config jest.json" | ||
}, | ||
"devDependencies": { | ||
"@types/debug": "^4.1.5", | ||
"@types/jest": "^26.0.23", | ||
"@types/node": "^12.18.3", | ||
"@types/pixelmatch": "^5.2.3", | ||
"@types/pngjs": "^6.0.0", | ||
"jest": "^26.6.3", | ||
"jsdoc-to-markdown": "^7.0.1", | ||
"pixelmatch": "^5.2.1", | ||
"pngjs": "^6.0.0", | ||
"typescript": "^4.2.3" | ||
}, | ||
"dependencies": { | ||
"debug": "^4.3.1" | ||
} | ||
} |
# nautical-charts | ||
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/philliphoff/nautical-charts/CI) | ||
![npm](https://img.shields.io/npm/v/nautical-charts) | ||
![GitHub](https://img.shields.io/github/license/philliphoff/nautical-charts) | ||
A pure JavaScript library for reading nautical chart files. In particular, for reading BSB-formatted (`.bsb` and `.kap`) files. | ||
@@ -11,36 +15,83 @@ | ||
## API | ||
## API Reference | ||
## Classes | ||
> This API is in considerable flux, subject to drastic change, and therefore has not been fully documented. | ||
<dl> | ||
<dt><a href="#MemoryStream">MemoryStream</a></dt> | ||
<dd><p>A readable stream for an in-memory byte array.</p> | ||
</dd> | ||
</dl> | ||
### `readChart(contents: Uint8Array): KapChart | undefined` | ||
## Functions | ||
Parses a chart from the contents of a buffer. | ||
<dl> | ||
<dt><a href="#parseChart">parseChart(stream)</a> ⇒</dt> | ||
<dd><p>Parses a BSB chart from a readable (e.g. file) stream.</p> | ||
</dd> | ||
<dt><a href="#parseMetadata">parseMetadata(textSegment)</a> ⇒</dt> | ||
<dd><p>Parses the text segment of a BSB chart and returns well-known metadata, if present.</p> | ||
</dd> | ||
<dt><a href="#writeRasterSegment">writeRasterSegment(rasterSegment, palette, buffer, bufferWidth)</a></dt> | ||
<dd><p>Writes the RLE encoded raster data of a BSB chart to a bitmap.</p> | ||
</dd> | ||
</dl> | ||
### `writeRasterSegment(rasterSegment: KapRasterRow[], palette: KapPalette, buffer: Buffer, bufferWidth: number): void` | ||
<a name="MemoryStream"></a> | ||
Writes the (run-length-encoded, or RLE format) raster segment of a chart to a buffer in bitmap (i.e. RGBA) format. This function is useful for converting the chart to a more accessable format (such as PNG, via [pngjs](https://www.npmjs.com/package/pngjs)). | ||
## MemoryStream | ||
A readable stream for an in-memory byte array. | ||
## Types | ||
**Kind**: global class | ||
<a name="new_MemoryStream_new"></a> | ||
> These types are in considerable flux, subject to drastic change, and therefore have not been fully documented. | ||
### new MemoryStream(contents, options) | ||
The constructor for the MemoryStream | ||
### `interface KapChart` | ||
A parsed BSB chart. | ||
| Param | Description | | ||
| --- | --- | | ||
| contents | The array from which to read. | | ||
| options | An optional set of readable stream options. | | ||
#### `readonly metadata?: KapMetadata;` | ||
<a name="parseChart"></a> | ||
Metadata related to the chart specifically parsed from the text segment. | ||
## parseChart(stream) ⇒ | ||
Parses a BSB chart from a readable (e.g. file) stream. | ||
#### `readonly rasterSegment?: KapRasterRow[];` | ||
**Kind**: global function | ||
**Returns**: A BSB chart. | ||
The rows that make up the raster segment of the chart. | ||
| Param | Description | | ||
| --- | --- | | ||
| stream | The stream from which to read the chart data. | | ||
#### `readonly textSegment?: KapTextEntry[];` | ||
<a name="parseMetadata"></a> | ||
The partially-processed entries that make up the text segment. | ||
## parseMetadata(textSegment) ⇒ | ||
Parses the text segment of a BSB chart and returns well-known metadata, if present. | ||
**Kind**: global function | ||
**Returns**: The metadata parsed from the chart. | ||
| Param | Description | | ||
| --- | --- | | ||
| textSegment | The text entries of the chart. | | ||
<a name="writeRasterSegment"></a> | ||
## writeRasterSegment(rasterSegment, palette, buffer, bufferWidth) | ||
Writes the RLE encoded raster data of a BSB chart to a bitmap. | ||
**Kind**: global function | ||
| Param | Description | | ||
| --- | --- | | ||
| rasterSegment | The rows of raster data for the chart. | | ||
| palette | The palette from which to obtain pixel values. | | ||
| buffer | The bitmap buffer in which to write the chart raster data. | | ||
| bufferWidth | The width of the bitmap buffer. | | ||
## License | ||
The MIT License (see [LICENSE.md](LICENSE.md)) | ||
MIT (see [LICENSE.md](LICENSE.md)) |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
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
671607
30
982
96
1
10
3
1
+ Addeddebug@^4.3.1
+ Addeddebug@4.3.7(transitive)
+ Addedms@2.1.3(transitive)