<p>Appwrite Storage allows you to manage files in your project. You can use it to store images, videos, documents, and other files for your projects. It provides APIs to upload, download, delete, and list files. Not only that Appwrite storage service provides APIs to manipulate images. Using the preview endpoint, you can crop, resize, rotate, add borders and border-radius and select the desired output format for your image. The preview API also allows you to change your image's quality, format, or compression, including WebP support for maximum optimization of your network bandwidth.
</p>

<h2><a href="/docs/storage#bucket" id="bucket">Buckets</a></h2>

<p>Storage buckets are similar to collections in the <a href="/docs/databases">Databases</a> service. The difference is buckets also provide more power to decide what kinds of files, what sizes you want to allow in that bucket, whether or not to encrypt the files, scan with antivirus, and more. Let's look at how we can create a bucket and configure it to your needs.</p>

<h3><a href="/docs/storage#createBucket" id="createBucket">Create Bucket</a></h3>

<p>You can create your bucket from your Appwrite project's dashboard, using any of our server-side SDKs, or directly using our REST API authenticated using an API Key. To create a bucket from the Appwrite Console, access your Storage dashboard from your project's left navigation panel. Click <b>Add Bucket</b> button and choose your bucket's name. You can also set a custom ID for your bucket instead of an auto-generated ID for convenience. This will create a new bucket and take you to its settings page, where you can configure various options for your bucket.</p>

<p>You can manage your buckets programmatically using one of Appwrite's Server <a href="/docs/sdks#server">SDKs</a> or REST API paired with an API Key. You can manage files with both Server and Client side.</p>

<h4><a href="/docs/storage#permission" id="permission">Permissions</a></h4>

<p>The Storage Service allows you to configure permissions at both the bucket level and the file level. When a user has the appropriate type of <a href="/docs/permissions/">access permissions</a> granted at <b>either</b> the bucket or the file level, they will be able to access the file. If the permission field is left empty, no one can access the file.</p>

<h5>File Level Permissions</h5>
<p>File level permissions grant access to individual files. File level permissions are only enabled if File Security is enabled in the settings of your bucket.
</p>

<h5>Bucket Level Permissions</h5>
<p>Bucket level permissions apply to every file in the bucket.</p>

<h4><a href="/docs/storage#bucketConfig" id="bucketConfig">More Bucket Configurations</a></h4>

<p>Storage buckets have many configuration options, including the type and maximum size of files in the bucket, whether encryption or anti-virus is enabled,  and the compression algorithm to use. If you look at the bucket settings or the REST API example above, you can find these configurations. Let's look at what those are:</p>

<table cellspacing="0" cellpadding="0" border="0" class="full margin-bottom-large">
    <thead>
        <tr>
            <th style="width: 250px">Parameter</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>allowedFileExtensions</td>
            <td>This parameter allows you to provide a list of file extensions that will be accepted into the bucket.</td>
        </tr>
        <tr>
            <td>maximumFileSize</td>
            <td>This parameter allows you to set the maximum size of a file that a bucket accepts. The buckets will accept any file less than or equal to the size provided here.</td>
        </tr>
        <tr>
            <td>encryption</td>
            <td>This parameter allows you to configure whether or not the files inside the bucket will be encrypted. We don't encrypt files bigger than 20MB.</td>
        </tr>
        <tr>
            <td>antivirus</td>
            <td>This parameter allows you to configure whether or not the files being added inside the bucket be scanned by antivirus. We don't scan files bigger than 20MB.</td>
        </tr>
    </tbody>
</table>

<p>You can learn more about storage buckets and APIs you can use to manage storage buckets from our <a href="/docs/server/storage">Storage documentation</a>. Now that we know how to create and configure buckets for our applications, let's look at how to manage files using the storage service.</p>

<h2><a href="/docs/storage#createFile" id="createFile">Create File</a></h2>

<p>After you create a bucket or have navigated to bucket details, you can access the <b>Files</b> tab so you can upload, view, delete and update files in the bucket using the Appwrite project's dashboard. You can also perform all those operations from Appwrite's client SDK, server SDKs, and REST APIs as long as you have the proper permission.</p>

<p>When you are in the <b>Files</b> tab, you can click <b>Add File</b> and select a file to upload. If the bucket is configured to accept the file type and size you are uploading, your file will be uploaded, and you will see the file in the list of files.
</p>

<p>You can also upload files programmatically using our SDKs:</p>

<ul class="phases clear" data-ui-phases>
    <li>
        <h3>Web</h3>
        <div class="ide" data-lang="javascript" data-lang-label="Web SDK">
            <pre class="line-numbers"><code class="prism language-javascript" data-prism>import { Client, Storage } from "appwrite";

const client = new Client()
    .setEndpoint('https://cloud.appwrite.io/v1')
    .setProject('[PROJECT_ID]');

const storage = new Storage(client);

const promise = storage.createFile(
    '[BUCKET_ID]',
    ID.unique(),
    document.getElementById('uploader').files[0]
);

promise.then(function (response) {
    console.log(response); // Success
}, function (error) {
    console.log(error); // Failure
});
            </code></pre>
        </div>
    </li>
    <li>
        <h3>Flutter</h3>
        <div class="ide" data-lang="dart" data-lang-label="Flutter SDK">
            <pre class="line-numbers"><code class="prism language-dart" data-prism>import 'package:appwrite/appwrite.dart';

void main() { // Init SDK
  final client = Client()
    .setEndpoint('https://cloud.appwrite.io/v1')
    .setProject('[PROJECT_ID]');

  final storage = Storage(client);

  final file = await storage.createFile(
    bucketId: '[BUCKET_ID]',
    fileId: ID.unique(),
    file: InputFile.fromPath(path: './path-to-files/image.jpg', filename: 'image.jpg'),
  );
}</code></pre>
        </div>
    </li>
    <li>
        <h3>Android</h3>
        <div class="ide" data-lang="kotlin" data-lang-label="Android SDK">
            <pre class="line-numbers"><code class="prism language-kotlin" data-prism>import io.appwrite.Client
import io.appwrite.services.Storage

suspend fun main() {
    val client = Client(applicationContext)
        .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        .setProject("[PROJECT_ID]") // Your project ID

    val storage = Storage(client)

    val file = storage.createFile(
        bucketId = "[BUCKET_ID]",
        fileId = ID.unique(),
        file = File("./path-to-files/image.jpg"),
    )
}</code></pre>
        </div>
    </li>
    <li>
        <h3>Apple</h3>
        <div class="ide" data-lang="swift" data-lang-label="Apple SDK">
            <pre class="line-numbers"><code class="prism language-swift" data-prism>import Appwrite

func main() async throws {
    let client = Client()
      .setEndpoint("https://cloud.appwrite.io/v1")
      .setProject("[PROJECT_ID]")

    let storage = Storage(client)

    let file = try await storage.createFile(
        bucketId: "[BUCKET_ID]",
        fileId: ID.unique(),
        file: InputFile.fromBuffer(yourByteBuffer,
            filename: "image.jpg",
            mimeType: "image/jpeg"
        )
    )
}</code></pre>
        </div>
    </li>
    <li>
        <h3>GraphQL</h3>
        <div class="ide" data-lang="http" data-lang-label="HTTP">
            <pre class="line-numbers"><code class="prism language-http" data-prism>POST /v1/storage/buckets/{bucketId}/files HTTP/1.1
Content-Type: multipart/form-data; boundary="cec8e8123c05ba25"
Content-Length: *Length of your entity body in bytes*
X-Appwrite-Project: [PROJECT_ID]

--cec8e8123c05ba25
Content-Disposition: form-data; name="operations"

{ "query": "mutation CreateFile($bucketId: String!, $fileId: String!, $file: InputFile!) { storageCreateFile(bucketId: $bucketId, fileId: $fileId, file: $file) { id } }", "variables": { "bucketId": "[BUCKET_ID]", "fileId": "[FILE_ID]", "file": null } }
--cec8e8123c05ba25
Content-Disposition: form-data; name="map"

{ "0": ["variables.file"] }
--cec8e8123c05ba25
Content-Disposition: form-data; name="0"; filename="file.txt"
Content-Type: text/plain

File content.

--cec8e8123c05ba25--</code></pre>
        </div>
    </li>
</ul>

<p>
    When you are trying to upload any files above 5MB, you will need to upload them in chunks for better reliability and performance. If you're using an Appwrite SDK, this is handled automatically. If you're not using an SDK, you can learn more about file handling in the <a href="/docs/rest#file-handling">REST API</a> docs.
</p>

<h2><a href="/docs/storage#file-input" id="file-input">File Input</a></h2>

<p>
    Every language and platform handles file inputs differently. This section documents the expected input type of each SDK. Where applicable, Appwrite provides a <code>InputFile</code> class to accept multiple file sources, like paths, buffers, streams, or plain text.
</p>

<h3><a href="/docs/storage#file-input-client" id="file-input-client">Client SDK</a></h3>
<ul class="phases clear" data-ui-phases>
<li>
    <h3>Web</h3>
    <p>
        The Appwrite Web SDK expects a <a href="https://developer.mozilla.org/en-US/docs/Web/API/File" target="_blank" rel="noopener">File</a> object for file creation. This is most commonly associated with DOM file inputs.
    </p>

    <p>
        For example, for the input tag <code><?php echo htmlentities('<input type="file" id="uploader" />'); ?></code>, you would call create file like this:
    </p>
    <div class="ide" data-lang="javascript" data-lang-label="Web SDK">
        <pre class="line-numbers"><code class="prism language-javascript" data-prism>const promise = storage.createFile(
    '[BUCKET_ID]',
    ID.unique(),
    document.getElementById('uploader').files[0]
);</code></pre>
    </div>

</li>
<li>
    <h3>Flutter</h3>
    <p>
        The Appwrite Flutter SDK expects an <code>InputFile</code> class for file inputs.
    </p>
    <table class="full text-size-small">
        <thead>
        <tr>
            <td style="width: 200px">Method</td>
            <td>Description</td>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td><code>InputFile.fromPath(path: [PATH], filename: [NAME], contentType: [MIME TYPE])</code></td>
            <td>Used to upload files from a provided path, <code>filename</code> and <code>contentType</code> are optional. Used for Flutter apps on mobile and desktop.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromBytes(bytes: [BYTE LIST], filename: [NAME], contentType: [MIME TYPE])</code></td>
            <td>Used to upload files from a byte list, <code>contentType</code> is optional. Used for Flutter apps on web</td>
        </tr>
        </tbody>
    </table>
</li>
<li>
    <h3>Android</h3>
    <p>
        The Appwrite Android SDK expects an <code>InputFile</code> class for file inputs.
    </p>
    <table class="full text-size-small">
        <thead>
        <tr>
            <td style="width: 200px">Method</td>
            <td>Description</td>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td><code>InputFile.fromPath(path: String)</code></td>
            <td>Used to upload files from a provided path.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromFile(file: File)</code></td>
            <td>Used to upload files from a <a href="https://docs.oracle.com/javase/8/docs/api/java/io/File.html" target="_blank" rel="noopener">File</a> object.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromBytes(bytes: ByteArray, filename: String, mimeType: String)</code></td>
            <td>Used to upload files from a <a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-byte-array/" target="_blank" rel="noopener">ByteArray</a> object. Specify the file <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank" rel="noopener">MIME type</a> using the <code>mimeType</code> param.</td>
        </tr>
        </tbody>
    </table>
</li>
<li>
    <h3>Apple</h3>
    <p>
        The Appwrite Apple SDK expects an <code>InputFile</code> class for file inputs.
    </p>
    <table class="full text-size-small">
        <thead>
        <tr>
            <td style="width: 200px">Method</td>
            <td>Description</td>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td><code>InputFile.fromPath(_ path: String)</code></td>
            <td>Used to upload files from a provided path.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromData(_ data: Data, filename: String, mimeType: String)</code></td>
            <td>Used to upload files from a <a href="https://developer.apple.com/documentation/foundation/data" target="_blank" rel="noopener">Data</a> object. Specify the file <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank" rel="noopener">MIME type</a> using the <code>mimeType</code> param.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromBuffer(_ buffer: ByteBuffer, filename: String, mimeType: String)</code></td>
            <td>Used to upload files from a <a href="https://swiftinit.org/reference/swift-nio/niocore/bytebuffer" target="_blank" rel="noopener">NIO Buffer</a> object. Specify the file <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank" rel="noopener">MIME type</a> using the <code>mimeType</code> param.</td>
        </tr>
        </tbody>
    </table>
</li>
</ul>

<h3><a href="/docs/storage#file-input-server" id="file-input-server">Server SDK</a></h3>
<ul class="phases clear" data-ui-phases>
<li>
    <h3>Node.js</h3>

    <p>
        The Appwrite NodeJS SDK expects an <code>InputFile</code> class for file inputs.
    </p>
    <table class="full text-size-small">
        <thead>
        <tr>
            <td style="width: 200px">Method</td>
            <td>Description</td>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td><code>InputFile.fromPath(filePath, filename)</code></td>
            <td>Used to upload files from a provided path.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromBuffer(buffer, filename)</code></td>
            <td>Used to upload files from a <a href="https://nodejs.org/api/buffer.html#buffer" target="_blank" rel="noopener">Buffer</a> object.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromBlob(blob, filename)</code></td>
            <td>Used to upload files from a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob" target="_blank" rel="noopener">Blob</a> object.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromStream(stream, filename, size)</code></td>
            <td>Used to upload files from a <a href="https://nodejs.org/api/stream.html#readable-streams" target="_blank" rel="noopener">Readable Stream</a> object.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromPlainText(content, filename)</code></td>
            <td>Used to upload files in plain text. Expects a string encoded in UTF-8.</td>
        </tr>
        </tbody>
    </table>
</li>
<li>
    <h3>PHP</h3>
    <p>
        The Appwrite PHP SDK expects an <code>InputFile</code> class for file inputs.
    </p>
    <table class="full text-size-small">
        <thead>
        <tr>
            <td style="width: 200px">Method</td>
            <td>Description</td>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td><code>InputFile.withPath(string $path, ?string $mimeType = null, ?string $filename = null)</code></td>
            <td>Used to upload files from a provided path.</td>
        </tr>
        <tr>
            <td><code>InputFile.withData(string $data, ?string $mimeType = null, ?string $filename = null)</code></td>
            <td>Used to upload files from a string.</td>
        </tr>
        </tbody>
    </table>
</li>
<li>
    <h3>Python</h3>
    <p>
        The Appwrite Python SDK expects an <code>InputFile</code> class for file inputs.
    </p>
    <table class="full text-size-small">
        <thead>
        <tr>
            <td style="width: 200px">Method</td>
            <td>Description</td>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td><code>InputFile.from_path(path)</code></td>
            <td>Used to upload files from a provided path.</td>
        </tr>
        <tr>
            <td><code>InputFile.from_bytes(bytes)</code></td>
            <td>Used to upload files from an array of bytes.</td>
        </tr>
        </tbody>
    </table>
</li>
<li>
    <h3>Ruby</h3>
    <p>
        The Appwrite Ruby SDK expects an <code>InputFile</code> class for file inputs.
    </p>
    <table class="full text-size-small">
        <thead>
        <tr>
            <td style="width: 200px">Method</td>
            <td>Description</td>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td><code>InputFile.from_path(path)</code></td>
            <td>Used to upload files from a provided path.</td>
        </tr>
        <tr>
            <td><code>InputFile.from_string(string)</code></td>
            <td>Used to upload files from a String.</td>
        </tr>
        <tr>
            <td><code>InputFile.from_bytes(bytes)</code></td>
            <td>Used to upload files from an array of bytes.</td>
        </tr>
        </tbody>
    </table>
</li>
<li>
    <h3>Deno</h3>    
    <p>
        The Appwrite Deno SDK expects an <code>InputFile</code> class for file inputs.
    </p>
    <table class="full text-size-small">
        <thead>
        <tr>
            <td style="width: 200px">Method</td>
            <td>Description</td>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td><code>InputFile.fromPath(filePath, filename)</code></td>
            <td>Used to upload files from a provided path.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromBuffer(buffer, filename)</code></td>
            <td>Used to upload files from a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array" target="_blank" rel="noopener">Uint8Array</a> object.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromPlainText(content, filename)</code></td>
            <td>Used to upload files in plain text. Expects a string encoded in UTF-8.</td>
        </tr>
        </tbody>
    </table>
</li>
<li>
    <h3>Dart</h3>
    <p>
        The Appwrite Dart SDK expects an <code>InputFile</code> class for file inputs.
    </p>
    <table class="full text-size-small">
        <thead>
        <tr>
            <td style="width: 200px">Method</td>
            <td>Description</td>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td><code>InputFile.fromPath(path: [PATH], filename: [NAME], contentType: [MIME TYPE])</code></td>
            <td>Used to upload files from a provided path, <code>filename</code> and <code>contentType</code> are optional.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromBytes(bytes: [BYTE LIST], filename: [NAME], contentType: [MIME TYPE])</code></td>
            <td>Used to upload files from a byte list, <code>contentType</code> is optional.</td>
        </tr>
        </tbody>
    </table>
</li>
<li>
    <h3>Kotlin</h3>
    <p>
        The Appwrite Kotlin SDK expects an <code>InputFile</code> class for file inputs.
    </p>
    <table class="full text-size-small">
        <thead>
        <tr>
            <td style="width: 200px">Method</td>
            <td>Description</td>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td><code>InputFile.fromPath(path: String)</code></td>
            <td>Used to upload files from a provided path.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromFile(file: File)</code></td>
            <td>Used to upload files from a <a href="https://docs.oracle.com/javase/8/docs/api/java/io/File.html" target="_blank" rel="noopener">File</a> object.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromBytes(bytes: ByteArray, filename: String, mimeType: String)</code></td>
            <td>Used to upload files from a <a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-byte-array/" target="_blank" rel="noopener">ByteArray</a> object. Specify the file <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank" rel="noopener">MIME type</a> using the <code>mimeType</code> param.</td>
        </tr>
        </tbody>
    </table>
    
</li>
<li>
    <h3>Swift</h3>
    <p>
        The Appwrite Swift SDK expects an <code>InputFile</code> class for file inputs.
    </p>
    <table class="full text-size-small">
        <thead>
        <tr>
            <td style="width: 200px">Method</td>
            <td>Description</td>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td><code>InputFile.fromPath(_ path: String)</code></td>
            <td>Used to upload files from a provided path.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromData(_ data: Data, filename: String, mimeType: String)</code></td>
            <td>Used to upload files from a <a href="https://developer.apple.com/documentation/foundation/data" target="_blank" rel="noopener">Data</a> object. Specify the file <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank" rel="noopener">MIME type</a> using the <code>mimeType</code> param.</td>
        </tr>
        <tr>
            <td><code>InputFile.fromBuffer(_ buffer: ByteBuffer, filename: String, mimeType: String)</code></td>
            <td>Used to upload files from a <a href="https://swiftinit.org/reference/swift-nio/niocore/bytebuffer" target="_blank" rel="noopener">NIO Buffer</a> object. Specify the file <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank" rel="noopener">MIME type</a> using the <code>mimeType</code> param.</td>
        </tr>
        </tbody>
    </table>
</li><li>
    <h3>.NET</h3>
    <p>
        The Appwrite .NET SDK expects an <code>InputFile</code> class for file inputs.
    </p>
    <table class="full text-size-small">
        <thead>
        <tr>
            <td style="width: 200px">Method</td>
            <td>Description</td>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td><code>InputFile.FromPath(string path)</code></td>
            <td>Used to upload files from a provided path.</td>
        </tr>
        <tr>
            <td><code>InputFile.FromStream(Stream stream, string filename, string mimeType)</code></td>
            <td>Used to upload files from a <a href="https://learn.microsoft.com/en-us/dotnet/api/system.io.stream?view=net-7.0" target="_blank" rel="noopener">Stream</a> object. Specify the file <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank" rel="noopener">MIME type</a> using the <code>mimeType</code> param.</td>
        </tr>
        <tr>
            <td><code>InputFile.FromBytes(byte[] bytes, string filename, string mimeType)</code></td>
            <td>Used to upload files from an array of bytes. Specify the file <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank" rel="noopener">MIME type</a> using the <code>mimeType</code> param.</td>
        </tr>
        </tbody>
    </table>
</li>
</ul>


<h2><a href="/docs/storage#imagePreview" id="imagePreview">Image Manipulation</a></h2>

<p>Another great built-in feature of Appwrite is the image manipulation feature. With Appwrite Storage's <a href="/docs/client/storage#storageGetFilePreview">preview endpoint</a> you can manipulate resolution, add borders and the border-radius, add background-color, set the opacity for the image, and get the image in the appropriate output format.
</p>

<p>This enables a wide range of possibilities! You can manipulate images resolution to display appropriately on responsive websites. You can also adjust the image border, background color, and border-radius to match the theming of your application. The Appwrite Storage also allows you to change the format and compression of your images for network transfer optimization and to help you speed your application. You can do all that without caring about how the image was originally uploaded.</p>

<p>Below you can find all the different parameters offered by the preview endpoint to manipulate the image.</p>

<table cellspacing="0" cellpadding="0" border="0" class="full margin-bottom-large">
    <thead>
        <tr>
            <th style="width: 250px">Parameter</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>height</td>
            <td>Set the height of the output image in pixels, the image will be resized keeping the aspect ratio intact. Accepts integer between 0-4000</td>
        </tr>
        <tr>
            <td>width</td>
            <td>Set the width of the output image in pixels, the image will be resized keeping the aspect ratio intact. Accepts integer between 0-4000</td>
        </tr>
        <tr>
            <td>gravity</td>
            <td>The gravity while cropping the image providing either width, height or both. Accepts any of: center, top-left, top, top-right, left, right, bottom-left, bottom, bottom-right</td>
        </tr>
        <tr>
            <td>quality</td>
            <td>Set the quality of the output image. Accepts integer between 0-100, where 100 is the highest quality.</td>
        </tr>
        <tr>
            <td>borderWidth</td>
            <td>Set a border with given width in pixels to the output image. Accepts integer between 0-100</td>
        </tr>
        <tr>
            <td>borderColor</td>
            <td>Set a border-color for the output image. Accepts any valid Hex color value without the leading #.</td>
        </tr>
        <tr>
            <td>borderRadius</td>
            <td>Set a border-radius in pixels. Accepts an integer between 0-4000.</td>
        </tr>
        <tr>
            <td>opacity</td>
            <td>Set opacity for the output image. Accepts a float value between 0-1, where 0 makes it transparent. Only works with output format supporting alpha channel like png.</td>
        </tr>
        <tr>
            <td>rotation</td>
            <td>Rotate the output image by a degree. Accepts an integer between -360 to 360.</td>
        </tr>
        <tr>
            <td>background</td>
            <td>Set a background-color. Accepts any valid Hex color value without the leading #. Only works with output format supporting alpha channel like png.</td>
        </tr>
        <tr>
            <td>output</td>
            <td>Set the output image format. If not provided, will use the original image's format. Supported formats are: jpg, jpeg, png, gif and webp</td>
        </tr>
    </tbody>
</table>


<h2><a href="/docs/storage#streaming" id="streaming">Downloading and Streaming with Range</a></h2>

<p>Appwrite supports streamed downloads using the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range" target="_blank">HTTP range header</a> to gracefully handle large files. If you are using our SDKs or console, nothing is different. Even if you want to download the whole file at once, even if you use the REST endpoint directly, there isn't any difference. However, if you want to get only a part of a file from storage, you can supply the range header and the server will respond with an appropriate chunk of the file.</p>