# Images

When an `Image` is created, it needs a way of providing Homey with its data. This can be either:

* an URL, available from anywhere on the internet
* a binary stream through the `getStream` method
* a local path to a static image which is shipped with the App.

{% hint style="warning" %}
Note: Images are limited to 5 MB.
{% endhint %}

{% hint style="info" %}
You can debug your images in the [Developer Tools](https://tools.developer.homey.app/tools/images).
{% endhint %}

## Creating an image

### Using an URL

URLs should be used when the image is available publicly on the internet.

{% tabs %}
{% tab title="JavaScript" %}
{% code title="/app.js" %}

```javascript
const Homey = require('homey');

class App extends Homey.App {
  async onInit() {
    const myImage = await this.homey.images.createImage();
    // the URL must start with https://
    myImage.setUrl("https://www.example.com/image.png");
  }
}

module.exports = App;
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="/app.mts" %}

```mts
import Homey from "homey";

export default class App extends Homey.App {
  async onInit(): Promise<void> {
    const myImage = await this.homey.images.createImage();
    // the URL must start with https://
    myImage.setUrl("https://www.example.com/image.png");
  }
}

```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code title="/app.py" %}

```python
from homey import app


class App(app.App):
    async def on_init(self) -> None:
        my_image = await self.homey.images.create_image()
        # the URL must start with https://
        my_image.set_url("https://www.example.com/image.png")


homey_export = App

```

{% endcode %}
{% endtab %}
{% endtabs %}

### Using a Stream

{% tabs %}
{% tab title="JavaScript" %}
Streams should be used when downloading an image that cannot be supplied using [`Image#setUrl()`](https://apps-sdk-v3.developer.homey.app/Image.html#setUrl). Using image streams involves writing data directly into a Node.js stream. Using streams requires homey version 2.2.0 or higher.

{% code title="/app.js" %}

```javascript
const Homey = require('homey');
const fetch = require("node-fetch");

class App extends Homey.App {
  async onInit() {
    const myImage = await this.homey.images.createImage();

    myImage.setStream(async (stream) => {
      const res = await fetch("http://192.168.1.100/image.png");
      if (!res.ok) {
        throw new Error("Invalid Response");
      }

      return res.body.pipe(stream);
    });
  }
}

module.exports = App;
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
Streams should be used when downloading an image that cannot be supplied using [`Image#setUrl()`](https://apps-sdk-v3.developer.homey.app/Image.html#setUrl). Using image streams involves writing data directly into a Node.js stream. Using streams requires homey version 2.2.0 or higher.

{% code title="/app.mts" %}

```mts
import Homey from "homey";
import fetch from "node-fetch";
import type { Writable } from "stream";

export default class App extends Homey.App {
  async onInit(): Promise<void> {
    const myImage = await this.homey.images.createImage();

    myImage.setStream(async (stream: Writable) => {
      const res = await fetch("http://192.168.1.100/image.png");
      if (!res.ok || res.body === null) {
        throw new Error("Invalid Response");
      }

      return res.body.pipe(stream);
    });
  }
}

```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
Streams should be used when downloading an image that cannot be supplied using [`Image#set_url()`](https://python-apps-sdk-v3.developer.homey.app/image.html#homey.image.Image.set_url). Using image streams involves writing data directly into a io.BytesIO stream. Using streams requires homey version 2.2.0 or higher.

{% code title="/app.py" %}

```python
from io import BytesIO

import aiohttp
from homey import app


class App(app.App):
    async def on_init(self) -> None:
        my_image = await self.homey.images.create_image()

        async def stream_image(stream: BytesIO):
            async with aiohttp.ClientSession() as session:
                async with session.get("http://192.168.1.100/image.png") as res:
                    if not res.ok:
                        raise Exception("Invalid Response")
                    stream.write(await res.read())

        my_image.set_stream(stream_image)


homey_export = App

```

{% endcode %}
{% endtab %}
{% endtabs %}

### Using a Path

Paths should be used when the image is locally available.

{% tabs %}
{% tab title="JavaScript" %}
{% code title="/app.js" %}

```javascript
const Homey = require('homey');

class App extends Homey.App {
  async onInit() {
    const myImage = await this.homey.images.createImage();
    myImage.setPath("/userdata/image.png");
  }
}

module.exports = App;
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="/app.mts" %}

```mts
import Homey from "homey";

export default class App extends Homey.App {
  async onInit(): Promise<void> {
    const myImage = await this.homey.images.createImage();
    myImage.setPath("/userdata/image.png");
  }
}

```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code title="/app.py" %}

```python
from homey import app


class App(app.App):
    async def on_init(self) -> None:
        my_image = await self.homey.images.create_image()
        my_image.set_path("/userdata/image.png")


homey_export = App

```

{% endcode %}
{% endtab %}
{% endtabs %}

## Updating the image

{% tabs %}
{% tab title="JavaScript" %}
Call [`Image#update()`](https://apps-sdk-v3.developer.homey.app/Image.html#update) when the image has been updated, and the front-end will download the image again.

When your image uses a Stream, the method provided in [`Image#setStream()`](https://apps-sdk-v3.developer.homey.app/Image.html#setStream) will be called again.

At any time, you can switch between delivery type by calling [`Image#setPath()`](https://apps-sdk-v3.developer.homey.app/Image.html#setPath), [`Image#setStream()`](https://apps-sdk-v3.developer.homey.app/Image.html#setStream) or [`Image#setURL()`](https://apps-sdk-v3.developer.homey.app/Image.html#setURL).
{% endtab %}

{% tab title="TypeScript" %}
Call [`Image#update()`](https://apps-sdk-v3.developer.homey.app/Image.html#update) when the image has been updated, and the front-end will download the image again.

When your image uses a Stream, the method provided in [`Image#setStream()`](https://apps-sdk-v3.developer.homey.app/Image.html#setStream) will be called again.

At any time, you can switch between delivery type by calling [`Image#setPath()`](https://apps-sdk-v3.developer.homey.app/Image.html#setPath), [`Image#setStream()`](https://apps-sdk-v3.developer.homey.app/Image.html#setStream) or [`Image#setURL()`](https://apps-sdk-v3.developer.homey.app/Image.html#setURL).
{% endtab %}

{% tab title="Python" %}
Call [`Image#update()`](https://python-apps-sdk-v3.developer.homey.app/image.html#homey.image.Image.update) when the image has been updated, and the front-end will download the image again.

When your image uses a Stream, the method provided in [`Image#set_stream()`](https://python-apps-sdk-v3.developer.homey.app/image.html#homey.image.Image.set_stream) will be called again.

At any time, you can switch between delivery type by calling [`Image#set_path()`](https://python-apps-sdk-v3.developer.homey.app/image.html#homey.image.Image.set_path), [`Image#set_stream()`](https://python-apps-sdk-v3.developer.homey.app/image.html#homey.image.Image.set_stream) or [`Image#set_url()`](https://python-apps-sdk-v3.developer.homey.app/image.html#homey.image.Image.set_url).
{% endtab %}
{% endtabs %}

## Retrieving an image

It is also possible to consume an image in your app, for instance through use of Flow Tokens.

```javascript
const { PassThrough } = require("stream");
const fetch = require("node-fetch");
const FormData = require("form-data");

//uploads an image to imgur and returns a link
async function uploadImage(image) {
  const stream = await image.getStream();

  const form = new FormData();

  form.append("image", stream, {
    contentType: stream.contentType,
    filename: stream.filename,
    name: "image",
  });

  form.append(
    "description",
    `This image can also be (temporarily) viewed at: ${image.cloudUrl} and ${image.localUrl}`
  );

  const response = await fetch("https://api.imgur.com/3/image", {
    method: "POST",
    //pipe through a passthrough stream, workarround for a node-fetch bug involving form-data streams without content length set.
    body: form.pipe(new PassThrough()),
    headers: {
      ...form.getHeaders(),
      Authorization: "Client-ID <YOUR_CLIENT_ID>",
    },
  });

  if (!response.ok) {
    throw new Error(response.statusText);
  }

  const { data } = await response.json();
  return data.link;
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://apps.developer.homey.app/advanced/images.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
