# imscJS

     _                                 _    _____ 
    (_)                               | |  / ____|
     _   _ __ ___    ___    ___       | | | (___  
    | | | '_ ` _ \  / __|  / __|  _   | |  \___ \ 
    | | | | | | | | \__ \ | (__  | |__| |  ____) |
    |_| |_| |_| |_| |___/  \___|  \____/  |_____/ 

## Introduction

imscJS is a JavaScript library for rendering
[IMSC](https://www.w3.org/TR/ttml-imsc/) documents to HTML5. IMSC is a profile
of [TTML 2](https://www.w3.org/TR/ttml2/) designed for subtitle and caption
delivery worldwide.

A sample web app that uses imscJS is available at https://imsc-renderer.sandflow.com/.

Documentation is available on [MDN](https://developer.mozilla.org/en-US/docs/Related/IMSC).

## Known issues and limitations

imscJS is primarily developed on Firefox and Chrome. Recent versions of Safari are intended to be supported nevertheless, albeit with potentially reduced capabilities.

The following IMSC features are currently not supported:

* [tts:disparity](https://www.w3.org/TR/ttml2/#style-attribute-disparity)
* [tts:luminanceGain](https://www.w3.org/TR/ttml2/#style-attribute-luminanceGain)
* [embedded fonts](https://www.w3.org/TR/ttml2/#embedded-content-vocabulary-font)

imscJS bugs are tracked at https://github.com/sandflow/imscJS/issues.

## Runtime dependencies

imscJS requires an XML parser. By default it uses the browser's native [`DOMParser`](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser), so no additional library is needed in a browser environment. In environments where `DOMParser` is not available, e.g. Node.js, the caller must provide `fromXML()` with a parser that implements the contract defined in [src/main/js/parser.js](src/main/js/parser.js), e.g. [sax-js](https://www.npmjs.com/package/sax).

Rendering to HTML5 requires a browser environment, but parsing an IMSC document and transforming it into ISDs does not.

## Development dependencies

(required) node.js (see [package.json](package.json) for a complete list of dependencies)

(recommended) git

## Quick start

* run `npm run build`.

* the resulting `dist/imsc.debug.js` (non-minified) or `dist/imsc.min.js` (minified) file is the imscJS library. For example, it can be included in a web page as follows:

```html
    <script src="imsc.min.js"></script>
```

See BUILD ARTIFACTS for a full list of build artifacts, and TESTS AND SAMPLES for a list of samples and tests available.

## Architecture

### API

imscJS renders an IMSC document in three distinct steps:

* `fromXML(xmlstring, errorHandler, metadataHandler, parser)` parses the document and returns a TT object. The latter contains opaque representation of the document and exposes the method `getMediaTimeEvents()` that returns a list of time offsets (in seconds) of the ISD, i.e. the points in time where the visual representation of the document change. The optional `parser` argument allows the caller to provide an alternative XML parser, e.g. in environments where the browser's native `DOMParser` is not available.

* `generateISD(tt, offset, errorHandler)` creates a canonical representation of the document (provided as a TT object generated by `fromXML()`) at a point in time (`offset` parameter). This point in time does not have to be one of the values returned by `getMediaTimeEvents()`. For example, given an ISOBMFF sample covering the interval `[a, b[`, `generateISD(tt, offset, errorHandler)` would be called first with `offset = a`, then in turn with offset set to each value of `getMediaTimeEvents()` that fall in the interval `]a, b[`.

* `renderHTML(isd, element, imgResolver, eheight, ewidth, displayForcedOnlyMode, errorHandler, previousISDState, enableRollUp)` renders an `isd` object returned by `generateISD()` into a newly-created `div` element that is appended to the `element`. The `element` must be attached to the DOM. The height and width of the child `div` element are equal to `eheight` and `ewidth` if not null, or `clientWidth` and `clientHeight` of the parent `element` otherwise. Images URIs specified in `smpte:background` attributes are mapped to image resource URLs by the `imgResolver` function. The latter takes the value of the `smpte:background` attribute URI and an `img` DOM element as input and is expected to set the `src` attribute of the `img` DOM element to the absolute URI of the image. `displayForcedOnlyMode` sets the (boolean) value of the IMSC displayForcedOnlyMode parameter. `enableRollUp` enables roll-up as specified in CEA 708. `previousISDState` maintains states across calls, e.g. for roll-up processing.

In each step, the caller can provide an `errorHandler` to be notified of events during processing. The `errorHandler` may define four methods: `info`, `warn`, `error` and `fatal`. Each is called with a string argument describing the event, and will cause processing to terminate if it returns `true`.

Inline documentation provides additional information.

### Modules

imscJS consists of the following ES modules at [src/main/js](src/main/js), which can be imported individually, or used together as the `imsc` global when loaded as a UMD bundle (see [Build](#build)):

* `main.js`: public entry point; exposes `fromXML()`, `renderHTML()`, `generateISD()` and `createSAXParserFromDOMParser()`
* `doc.js`: parses an IMSC document into an in-memory TT object
* `parser.js`: defines the XML parser contract expected by `doc.js`
* `dom_to_parser.js`: implements the XML parser contract using the browser's `DOMParser`
* `isd.js`: generates an ISD object from a TT object
* `html.js`: generates an HTML fragment from an ISD object
* `names.js`: common constants
* `styles.js`: defines TTML styling attributes processing
* `utils.js`: common utility functions
* `error.js`: defines error handling utilities used across modules

## Build

imscJS is built using the `build` NPM script, which bundles the library.

The `dist` directory contains the following build artifacts:

* `imsc.debug.js`: Non-minified UMD build.
* `imsc.min.js`: Minified UMD build.
* `imsc.all.debug.js` and `imsc.all.min.js` (**deprecated**): Identical to
  `imsc.debug.js` and `imsc.min.js`, only for compatibility with imscJS 1.x and
  subject to removal in a future release.
* `main/`: ES modules and TypeScript type declarations, used when the library is imported as an NPM package.

## Releases

imscJS is released as an NPM package under [imsc](https://www.npmjs.com/package/imsc). The `dev` distribution tag indicates pre-releases.

Builds/dist are available on the [unpkg](https://unpkg.com/) CDN under the [`dist`](https://unpkg.com/browse/imsc/dist/) directory.

To access the latest builds, please consult the [release page](https://github.com/sandflow/imscJS/releases).

## Tests and samples

### W3C Test Suite

The headless script [src/test/script/gen-render-package.mjs](src/test/script/gen-render-package.mjs) can be used to generate PNG renderings as well as intermediary files (JSON document, ISD documents and HTML documents) from the [W3C IMSC test suite](https://github.com/w3c/imsc-tests).

```sh
npm run gen-imsc1
npm run gen-imsc1_1
npm run gen-imsc1_3
```

[src/test/script/compare_renders.py](src/test/script/compare_renders.py) compares two such render outputs (unzipped), performing byte-level, JSON/HTML and pixel-level PNG diffs, and optionally generating an HTML comparison report.

```sh
pipenv install
pipenv run python3 src/test/script/compare_renders.py <unzipped renders-imsc1> <unzipped renders-imsc1_1>
```

[src/test/script/gen-compare-site.mjs](src/test/script/gen-compare-site.mjs) generates, under `build/compare`, a static website that compares imscJS renders with the reference PNGs of the [W3C IMSC test suite](https://github.com/w3c/imsc-tests).

```sh
npm run build
npm run gen-compare-site
```

### Unit tests

Unit tests run using Node's built-in [test runner](https://nodejs.org/api/test.html) and are located at [src/test/js](src/test/js). They can be run with:

```sh
npm test
```

Some unit tests validate rendering output against the reference files at [src/test/resources/reference-files](src/test/resources/reference-files). These reference files are generated from the [W3C IMSC test suite](https://github.com/w3c/imsc-tests) by running:

```sh
npm run gen-reference-files
```

## Notable directories and files

* [package.json](package.json): NPM package definition

* [eslint.config.js](eslint.config.js): ESLint configuration

* [tsconfig.json](tsconfig.json): TypeScript configuration used to generate the type declarations in `dist/main`

* [rollup.config.js](rollup.config.js): Rollup configuration used to bundle `dist/main` into the UMD builds at `dist/imsc.debug.js` and `dist/imsc.min.js`

* [Pipfile](Pipfile): [pipenv](https://pipenv.pypa.io/) dependency declaration for `compare_renders.py`

* [LICENSE](LICENSE): License under which imscJS is made available

* [CONTRIBUTING](CONTRIBUTING): Certification required of contributions to imscJS

* [src/main/js](src/main/js): JavaScript modules

* [src/test](src/test): Test files

* [dist](dist): Built libraries
