ابرووا
شروع رایگان
☰ فهرست مستندات · تبدیل تصویر
به‌زودی. Abrova Storage به‌زودی فعال می‌شود. این صفحه توضیح می‌دهد چطور کار خواهد کرد؛ هنوز قابل استفاده نیست.
این صفحه هنوز ترجمه نشده — نسخه‌ی انگلیسی نمایش داده می‌شود. English

Image Transforms

On-the-fly image processing for Abrova Storage — resize, format conversion, quality, blur, sharpen, rotate and all five fit modes; HEIC photos; header-free public image URLs for public buckets; caching, variant limits, usage and transform error codes.

به‌روزرسانی: ۵ آبان ۱۴۰۵

Transform images on the fly with resizing, format conversion, and quality optimization. The original file is never changed. Each size / format of an image is made once and kept: later requests for the same options are served from the cache and don't count as a new transform.

Use WebP or AVIF.

Use WebP or AVIF formats for modern browsers to reduce file sizes by up to 30% compared to JPEG. Ask for them explicitly with f=webp or f=avif.

Transform Parameters#

OptionTypeRequiredDescription
width (w)Integer-Target width in pixels, 1-4096 (larger values are cut to 4096)
height (h)Integer-Target height in pixels, 1-4096
fitStringcoverResize mode: cover, contain, fill, inside, outside
format (f)StringjpegOutput format: jpeg, png, webp, avif
quality (q)Integer80Compression quality, 1-100
blurNumber-Blur effect, 0-20
sharpenNumber-Sharpen effect, 0-10
rotateInteger-Rotation in degrees (multiples of 90 recommended)

Any other value for f or fit, or blur / sharpen out of range, is refused with invalid_transform. The SDKs check the options before they build a URL.

Which images can be transformed

JPEG, PNG, WebP, GIF, AVIF, HEIC / HEIF (iPhone and Android camera photos), TIFF and SVG. For animated GIF and PNG, the first frame is used. The orientation a phone stores is applied, so portrait photos come out upright. Images up to 25 MB and 50 megapixels can be transformed.

Showing a transformed image#

Public buckets: a link with no headers

Add the options to the file's public link:

text
https://storage.abrova.ir/public/<bucketId>/<path>?w=600&f=webp

It needs no key, token or header, so it goes straight into <img src>, srcset, CSS, e-mails or Image.network(url). The SDKs build it for you with getPublicUrl(fileId, …options), and publicImageUrl(link, …options) builds it from a public link you stored earlier, without a request:

typescript
// Web (React Native and Node.js are the same)
import { publicImageUrl } from '@abrova/storage-web';

img.src = await storage.getPublicUrl(file.id, { width: 600, format: 'webp' });

const at = (width: number) => publicImageUrl(savedLink, { width, format: 'webp' });
img.srcset = `${at(600)} 600w, ${at(1200)} 1200w`;
dart
// Flutter
final url = await storage.getPublicUrl(file.id,
    transforms: const ImageTransforms(width: 600, format: 'webp'));
Image.network(url);
  • Same options, same URL. Options are read in any order with defaults applied, so ?w=300&f=webp and ?f=webp&w=300&q=80 are the same image. Other query parameters are ignored.
  • Cached. Browsers and other caches may keep an image for up to a day. When you replace a file's content, new requests get the new image; copies already cached can show the old one until they expire.
  • Use a few fixed sizes. One image keeps at most 50 different option sets. A new set beyond that is refused with too_many_variants (429); the existing ones keep working. Pick a few sizes (for example 200, 600 and 1200 wide) instead of the exact size of every view.
  • Private buckets have no public link: getPublicUrl fails with 403, and a /public link answers 404.

Private buckets: send the headers

getTransformUrl() returns https://storage.abrova.ir/api/v1/transform/<fileId>?…. That address needs the x-api-key and x-user-token headers and follows the bucket's read rules, so a plain <img src> or Image.network(url) without headers is refused. Load it with something that sends headers:

dart
// Flutter: Image.network can send headers
Image.network(
  storage.getTransformUrl(fileId, transforms: ImageTransforms(width: 200, height: 200, fit: 'cover', format: 'webp')),
  headers: {'x-api-key': 'ab_live_xxxxxxxxxxxx', 'x-user-token': userToken},
);
typescript
// Browser: fetch with headers, then show the bytes
const res = await fetch(storage.getTransformUrl(fileId, { width: 200, height: 200, fit: 'cover', format: 'webp' }), {
  headers: { 'x-api-key': 'ab_live_xxxxxxxxxxxx', 'x-user-token': userToken },
});
img.src = URL.createObjectURL(await res.blob());

React Native's <Image source={{ uri, headers }}>, and Coil or Glide on Android, can send the same headers. You can also download() the file, or show it from a signed link your server makes.

Usage and billing#

500 transforms are free every month; the price above that is set at launch and will be paid from your prepaid wallet. When the free transforms are used up and the wallet cannot pay for more, transform requests answer plan_feature_locked (403); the plain file and its public link always work. Transforms count each new size / format of an image once; showing it again doesn't count as a new transform. Bandwidth counts the bytes of the transformed image.

Transform errors#

When an image can't be made, the answer is JSON instead of an image, with statusCode, code and a message you can show to your users. The SDKs expose the codes as StorageErrorCode constants.

StatuscodeMeaning
400invalid_transformAn option isn't allowed (the message names it).
400not_an_imageThe file isn't an image.
415image_format_not_supportedThe image format can't be resized (for example BMP, ICO, PSD, JPEG 2000, JPEG XL, RAW / DNG).
413image_too_largeThe image has more than 50 megapixels.
413source_too_largeThe image file is over 25 MB.
422image_damagedThe image is damaged or incomplete (it may not have finished uploading).
403plan_feature_lockedNo transforms left: the free monthly transforms are used up and the wallet cannot pay for more.
429too_many_variantsPublic image URLs: this image already has 50 sizes / formats.
503transform_busyImage processing is busy. Retry after the Retry-After header's seconds. An img element fires error: set its src again after a short wait.

Common Use Cases#

text
// Avatar thumbnail (100x100, square crop)
?w=100&h=100&fit=cover&f=webp&q=80

// Responsive image (max 800px wide, maintain ratio)
?w=800&f=webp&q=85

// Low-quality placeholder (tiny, blurred - for lazy loading)
?w=20&blur=10&f=webp&q=30

// Product image (exact size, white background for contain)
?w=600&h=600&fit=contain&f=jpeg&q=90

// Gallery preview (medium size, optimized)
?w=400&h=300&fit=cover&f=webp&q=75

// Hero image (large, high quality)
?w=1920&h=1080&fit=cover&f=webp&q=90

Fit Modes Explained#

  • cover — Resize to cover the target dimensions, cropping if necessary. Best for avatars and thumbnails.
  • contain — Resize to fit within dimensions, preserving aspect ratio. May add padding.
  • fill — Stretch to exactly match dimensions. May distort the image.
  • inside — Resize to fit inside dimensions without upscaling.
  • outside — Resize to cover dimensions without downscaling.
این صفحه مفید بود؟
گزارش مشکل