# mosaic-image-stream

> Streaming mosaic of multiple images into a single image

Latest version **1.0.2** (published 2017-01-28) · MIT license · 0 weekly downloads

## Install

```sh
npm install mosaic-image-stream
pnpm add mosaic-image-stream
yarn add mosaic-image-stream
bun add mosaic-image-stream
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.0.2 |
| Published | 2017-01-28 |
| First published | 2016-08-29 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 7 |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 18 |
| Author | Gregor MacLennan |
| Maintainers | gmaclennan |
| Keywords | mosaic, image, stream, join, merge, stitch |

## Links

- npm: https://www.npmjs.com/package/mosaic-image-stream
- Repository: https://github.com/digidem/mosaic-image-stream
- Homepage: https://github.com/digidem/mosaic-image-stream#readme
- Issues: https://github.com/digidem/mosaic-image-stream/issues
- npm.io page: https://npm.io/package/mosaic-image-stream

## Dependencies (7)

- [from2](https://npm.io/package/from2.md) ^2.3.0
- [pumpify](https://npm.io/package/pumpify.md) ^1.3.5
- [inherits](https://npm.io/package/inherits.md) ^2.0.1
- [multistream](https://npm.io/package/multistream.md) ^2.1.0
- [block-stream2](https://npm.io/package/block-stream2.md) ^1.1.0
- [interleave-stream](https://npm.io/package/interleave-stream.md) ^1.0.2
- [buffer-peek-stream](https://npm.io/package/buffer-peek-stream.md) ^1.0.1

## Alternatives

- [byte-size](https://npm.io/package/byte-size.md) — 2.1M weekly downloads
- [speed-limiter](https://npm.io/package/speed-limiter.md) — 16.0K weekly downloads
- [@powersync/node](https://npm.io/package/@powersync/node.md) — 10.9K weekly downloads
- [@ledgerhq/coin-cardano](https://npm.io/package/@ledgerhq/coin-cardano.md) — 1.0K weekly downloads
- [@jayesol/jayeson.lib.streamfinder](https://npm.io/package/@jayesol/jayeson.lib.streamfinder.md) — 1.0K weekly downloads

## Recent versions

- 1.0.2 (latest) — 2017-01-28
- 1.0.1 — 2016-08-29
- 1.0.0 — 2016-08-29

## README

# mosaic-image-stream

[![npm](https://img.shields.io/npm/v/mosaic-image-stream.svg)](https://www.npmjs.com/package/mosaic-image-stream)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?maxAge=2592000)](http://standardjs.com/)

> Streaming mosaic of multiple images into a single image

Take a 2-D array of input [`pixel-streams`](https://github.com/devongovett/pixel-stream) and mosaic them together into a single image. Everything is streams, so you can theoretically mosaic thousands of images into a megapixel image without much memory usage.

## Table of Contents

- [Installation](#installation)
- [Usage](#usage)
- [API](#api)
- [Contribute](#contribute)
- [License](#license)

## Install

```
npm i mosaic-image-stream
```

## Usage

See [examples](./example).

Mosaic local file streams:

```js
var fs = require('fs')
var path = require('path')
var PNGDecoder = require('png-stream/decoder')
var PNGEncoder = require('png-stream/encoder')

var Mosaic = require('../')

var baseName = path.join(__dirname, 'images/image')

var streams = [
  [
    fs.createReadStream(baseName + '1.png').pipe(new PNGDecoder()),
    fs.createReadStream(baseName + '2.png').pipe(new PNGDecoder()),
    fs.createReadStream(baseName + '3.png').pipe(new PNGDecoder())
  ],
  [
    fs.createReadStream(baseName + '4.png').pipe(new PNGDecoder()),
    fs.createReadStream(baseName + '5.png').pipe(new PNGDecoder()),
    fs.createReadStream(baseName + '6.png').pipe(new PNGDecoder())
  ],
  [
    fs.createReadStream(baseName + '7.png').pipe(new PNGDecoder()),
    fs.createReadStream(baseName + '8.png').pipe(new PNGDecoder()),
    fs.createReadStream(baseName + '9.png').pipe(new PNGDecoder())
  ]
]

Mosaic(streams, {height: 300})
  .pipe(new PNGEncoder())
  .pipe(fs.createWriteStream(path.join(__dirname, 'file_mosaic.png')))
```

The giant wallmap of the Middle East you've always wanted (17,000px x 17,000px):

```js
var fs = require('fs')
var path = require('path')
var request = require('request')
var JPGDecoder = require('jpg-stream/decoder')
var JPGEncoder = require('jpg-stream/encoder')
var tilebelt = require('tilebelt')

var MAPBOX_TOKEN = 'pk.eyJ1IjoiZ21hY2xlbm5hbiIsImEiOiJSaWVtd2lRIn0.ASYMZE2HhwkAw4Vt7SavEg'
var urlBase = 'https://api.mapbox.com/v4/mapbox.streets/'

var Mosaic = require('../')

var zoom = 8
var tl = tilebelt.pointToTile(24, 48, zoom)
var br = tilebelt.pointToTile(72, 9, zoom)

var size = [br[0] - tl[0] + 1, br[1] - tl[1] + 1]
var factories = Array(size[0]).fill().map((v, i) => {
  var count = 0
  return function (cb) {
    var x = tl[0] + i
    var y = tl[1] + count
    if (++count > size[1]) return cb(null, null)
    var url = urlBase + zoom + '/' + x + '/' + y + '@2x.jpg?access_token=' + MAPBOX_TOKEN
    cb(null, request(url).pipe(new JPGDecoder()).on('error', err => {
      console.error(url)
      console.error(err)
    }))
  }
})

Mosaic(factories, size[1] * 512)
  .on('error', console.error)
  .pipe(new JPGEncoder())
  .pipe(fs.createWriteStream(path.join(__dirname, 'map_mosaic.jpg')))
```

Mosaic a whole bunch of images from Flickr:

```js
var fs = require('fs')
var path = require('path')
var request = require('request')
var JPEGDecoder = require('jpg-stream/decoder')
var JPEGEncoder = require('jpg-stream/encoder')

var Mosaic = require('../')

var reqUrl = 'https://api.flickr.com/services/rest/?' +
  'method=flickr.photos.search&' +
  'api_key=ea621d507593aa247dcaa792268b93d7&' +
  'tags=portrait&' +
  'sort=interestingness-desc&' +
  'media=photos&' +
  'extras=url_q&' +
  'format=json&' +
  'nojsoncallback=1&' +
  'per_page=500'

// One of the images Flickr returns does not have a height of 150px, even though the Flickr API thinks it does
var badUrl = 'https://farm2.staticflickr.com/1554/24516806801_084046c4dc_q.jpg'

var size = [15, 15]

request(reqUrl, function (err, resp, body) {
  if (err) return console.error(err)
  var urls = JSON.parse(body).photos.photo
    .map(d => d.url_q)
    .filter(d => d !== badUrl)
  var factories = Array(size[0]).fill().map((v, i) => {
    var count = 0
    return function (cb) {
      var url = urls[count + i * size[1]]
      if (++count > size[1]) return cb(null, null)
      cb(null, request(url).pipe(new JPEGDecoder()))
    }
  })

  Mosaic(factories, {height: size[1] * 150})
    .on('error', console.error)
    .pipe(new JPEGEncoder())
    .pipe(fs.createWriteStream(path.join(__dirname, 'flickr_mosaic.jpg')))
})
```

Input streams must be [`pixel-streams`](https://github.com/devongovett/pixel-stream). If you want to stream raw image data, stream it through a `pixel-stream` constructed with your image width, height and color space:

```js
myRawImageStream.pipe(new PixelStream(myImageWidth, myImageHeight, {colorSpace: myImageColorSpace}))
```

## API

```js
var Mosaic = require('mosaic-image-stream')
```

### Mosaic(streams, height)

Where:

- `streams` - a 2-d array of input stream, columns, then rows: e.g. `streams = [[row1col1, row2col2], [row1col2, row2col2]]`
- `height` - the total height of the input streams (width can be calculated on the fly from input images)

All input streams *must* have the same dimensions and color space - the output stream will throw an error if they differ, or if the total height of the input streams does not match the height specified.

Returns a [`pixel-stream`](https://github.com/devongovett/pixel-stream).

## Contribute

PRs accepted.

Small note: If editing the Readme, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.

## License

MIT © Gregor MacLennan / Digital Democracy

---
_Source: https://npm.io/package/mosaic-image-stream · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
