react-shopwave-connect 0.4.4 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -1
- package/dist/core/index.cjs +215 -25
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +102 -5
- package/dist/core/index.d.ts +102 -5
- package/dist/core/index.js +210 -26
- package/dist/core/index.js.map +1 -1
- package/dist/hooks/index.cjs +31 -25
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.js +31 -25
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.cjs +215 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +102 -5
- package/dist/index.d.ts +102 -5
- package/dist/index.js +210 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/core/index.d.cts
CHANGED
|
@@ -913,11 +913,12 @@ declare const SHOPWAVE_LOOKUPS: Readonly<Record<LookupKind, LookupDefinition>>;
|
|
|
913
913
|
//#endregion
|
|
914
914
|
//#region src/core/imageFit.d.ts
|
|
915
915
|
/**
|
|
916
|
-
* Browser helpers for getting an image to
|
|
916
|
+
* Browser helpers for getting an image to the right size before upload.
|
|
917
917
|
*
|
|
918
|
-
* Shopwave doesn't resize uploads,
|
|
919
|
-
*
|
|
920
|
-
*
|
|
918
|
+
* Shopwave doesn't resize uploads, so images are scaled and centre-cropped in
|
|
919
|
+
* the browser: to an exact size for the merchant image slots
|
|
920
|
+
* ({@link fitImageToSize}), or to a rule (ratio, minimum, maximum) with
|
|
921
|
+
* {@link prepareImage}, which apps use to give each kind of image its own rule.
|
|
921
922
|
*/
|
|
922
923
|
/** Source rectangle to draw so the image covers `dstWidth × dstHeight` (centre crop, no stretching). */
|
|
923
924
|
interface CropRect {
|
|
@@ -951,6 +952,102 @@ interface FitImageOptions {
|
|
|
951
952
|
* input, with the output type's extension.
|
|
952
953
|
*/
|
|
953
954
|
declare function fitImageToSize(file: Blob, width: number, height: number, options?: FitImageOptions): Promise<File>;
|
|
955
|
+
/**
|
|
956
|
+
* How an image must end up before upload. Every field is optional; give an
|
|
957
|
+
* exact size (`width` + `height`) or an `aspectRatio`, not both.
|
|
958
|
+
*
|
|
959
|
+
* Images are always scaled down first and then centre-cropped (never
|
|
960
|
+
* stretched): the kept area is the largest one with the right shape.
|
|
961
|
+
*
|
|
962
|
+
* @example
|
|
963
|
+
* // "Cropped to 100:77, at least 600 × 462", at most 2000 px on the long side
|
|
964
|
+
* { aspectRatio: "100:77", minWidth: 600, minHeight: 462, maxLongSide: 2000 }
|
|
965
|
+
* // Exactly 600 × 462
|
|
966
|
+
* { width: 600, height: 462 }
|
|
967
|
+
* // Any shape, scaled down to fit 2000 px
|
|
968
|
+
* { maxLongSide: 2000 }
|
|
969
|
+
*/
|
|
970
|
+
interface ImageRule {
|
|
971
|
+
/** Exact output width (needs `height`). */
|
|
972
|
+
width?: number;
|
|
973
|
+
/** Exact output height (needs `width`). */
|
|
974
|
+
height?: number;
|
|
975
|
+
/** Shape to crop to: `1.3`, `"100:77"`, `"100/77"` or `[100, 77]`. */
|
|
976
|
+
aspectRatio?: number | string | readonly [number, number];
|
|
977
|
+
/** Smallest acceptable output; a smaller image is refused (see `allowUpscale`). */
|
|
978
|
+
minWidth?: number;
|
|
979
|
+
minHeight?: number;
|
|
980
|
+
/** Largest output; a bigger image is scaled down to fit. */
|
|
981
|
+
maxWidth?: number;
|
|
982
|
+
maxHeight?: number;
|
|
983
|
+
/** Largest output on the longer side, whichever it is. */
|
|
984
|
+
maxLongSide?: number;
|
|
985
|
+
/** Enlarge a too-small image instead of refusing it. Default false. */
|
|
986
|
+
allowUpscale?: boolean;
|
|
987
|
+
}
|
|
988
|
+
/** What {@link prepareImage} will do to an image, worked out without touching it. */
|
|
989
|
+
interface ImageFitPlan {
|
|
990
|
+
/** The area of the source that's kept. */
|
|
991
|
+
crop: CropRect;
|
|
992
|
+
/** Output size. */
|
|
993
|
+
width: number;
|
|
994
|
+
height: number;
|
|
995
|
+
/** True when the source already fits the rule, so it can be uploaded as it is. */
|
|
996
|
+
unchanged: boolean;
|
|
997
|
+
}
|
|
998
|
+
/** A rule that can't be met by any image (a mistake in the rule, not the image). */
|
|
999
|
+
declare class ImageRuleError extends Error {
|
|
1000
|
+
constructor(message: string);
|
|
1001
|
+
}
|
|
1002
|
+
/** The image is smaller than the rule's minimum (and `allowUpscale` is off). */
|
|
1003
|
+
declare class ImageTooSmallError extends Error {
|
|
1004
|
+
/** The smallest size the rule accepts. */
|
|
1005
|
+
readonly required: ImageSize;
|
|
1006
|
+
/** The largest area of the right shape the image could give. */
|
|
1007
|
+
readonly actual: ImageSize;
|
|
1008
|
+
constructor(required: ImageSize, actual: ImageSize);
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* An aspect ratio as width ÷ height: `"100:77"`, `"100/77"`, `[100, 77]` →
|
|
1012
|
+
* 1.2987…; `1.3` → 1.3. Throws {@link ImageRuleError} for anything else.
|
|
1013
|
+
*/
|
|
1014
|
+
declare function parseAspectRatio(value: number | string | readonly [number, number]): number;
|
|
1015
|
+
/** Throws {@link ImageRuleError} when the rule contradicts itself. */
|
|
1016
|
+
declare function checkImageRule(rule: ImageRule): void;
|
|
1017
|
+
/**
|
|
1018
|
+
* Works out what to do to a `source`-sized image to meet `rule`: the centred
|
|
1019
|
+
* crop of the right shape (the largest one), then the output size (scaled
|
|
1020
|
+
* down to the maximum, never below the minimum). Pure: no browser needed.
|
|
1021
|
+
*
|
|
1022
|
+
* Throws {@link ImageTooSmallError} when the crop is below the minimum (or
|
|
1023
|
+
* the exact size) and `allowUpscale` is off, and {@link ImageRuleError} for a
|
|
1024
|
+
* contradictory rule.
|
|
1025
|
+
*
|
|
1026
|
+
* @example
|
|
1027
|
+
* planImageFit({ width: 6000, height: 4000 }, { aspectRatio: "100:77", minWidth: 600, minHeight: 462, maxLongSide: 2000 })
|
|
1028
|
+
* // → crop { sx: 403, sy: 0, sw: 5194, sh: 4000 }, 2000 × 1540
|
|
1029
|
+
*/
|
|
1030
|
+
declare function planImageFit(source: ImageSize, rule: ImageRule): ImageFitPlan;
|
|
1031
|
+
interface PrepareImageOptions {
|
|
1032
|
+
/** Output type. Default: the source's type when it's PNG, JPEG or WebP, else PNG. */
|
|
1033
|
+
type?: "image/png" | "image/jpeg" | "image/webp";
|
|
1034
|
+
/** 0–1, for JPEG and WebP. Default 0.9. */
|
|
1035
|
+
quality?: number;
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Returns the image meeting `rule` ({@link planImageFit}): centre-cropped to
|
|
1039
|
+
* the right shape and scaled in a single draw. An image that already fits is
|
|
1040
|
+
* returned untouched (same bytes). Browser only.
|
|
1041
|
+
*
|
|
1042
|
+
* Throws {@link ImageTooSmallError} (show `required` and `actual` to the
|
|
1043
|
+
* person) or {@link ImageRuleError}; an unreadable file rejects with the
|
|
1044
|
+
* browser's decoding error.
|
|
1045
|
+
*
|
|
1046
|
+
* @example
|
|
1047
|
+
* const ready = await prepareImage(file, { aspectRatio: "100:77", minWidth: 600, minHeight: 462, maxLongSide: 2000 });
|
|
1048
|
+
* await uploadImage(ready, { kind: "product", prefix: "product" });
|
|
1049
|
+
*/
|
|
1050
|
+
declare function prepareImage(file: Blob, rule: ImageRule, options?: PrepareImageOptions): Promise<File>;
|
|
954
1051
|
//#endregion
|
|
955
1052
|
//#region src/core/upload.d.ts
|
|
956
1053
|
interface UploadImageParams {
|
|
@@ -1278,5 +1375,5 @@ declare function productImageRole(value: unknown): UploadPrefix | null;
|
|
|
1278
1375
|
*/
|
|
1279
1376
|
declare function toStoredProductImages(images: unknown): string[];
|
|
1280
1377
|
//#endregion
|
|
1281
|
-
export { Basket, BasketFilters, BasketItem, BasketPagination, BasketReportRow, BasketSummary, Category, CategoryResponse, CombineBasketRowsParams, Consumer, ConsumerResponse, CropRect, DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, DeletableEntityKind, Employee, EmployeeResponse, EntityDefinition, EntityId, EntityInput, EntityKind, EntityTypes, ErrorMessage, Extras, FetchByIdParams, FetchCategoriesParams, FetchEmployeesParams, FetchProductsParams, FetchPromotionsParams, FetchStoresParams, FitImageOptions, ImageSize, LookupDefinition, LookupKind, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, Merchant, MerchantColourKey, MerchantColourSet, MerchantColours, MerchantImageIds, MerchantImageSlot, MerchantImageSlotDefinition, MerchantLinkKey, MerchantLinks, MerchantPatch, MerchantResponse, MessageInfo, ParsedBasket, Product, ProductInstance, ProductInstanceInput, ProductInstances, ProductResponse, ProductSaveInput, Promotion, PromotionResponse, PromotionRuleSet, ReportData, ReportKey, ReportQuery, ReportQueryMap, ReportResponse, RepricedInstance, RequestOptions, ResourceDefinition, ResourceKind, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, Saved, SessionStatus, ShopwaveApiError, ShopwaveErrorMap, Store, StoreResponse, SubmitEntityArgs, SubmitEntityResponse, SuccessMessage, UPLOAD_KINDS, UPLOAD_PREFIXES, UpdateMerchantOptions, UploadImageParams, UploadKind, UploadMerchantImageOptions, UploadPrefix, UploadedImage, User, UserEmployee, UserResponse, WritableEntityKind, apiDelete, apiGet, apiRequest, apiResponse, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProductInstanceTags, fetchProductTags, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, isUploadPrefix, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, normalizeTagList, parseBasketReportData, productImageRole, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, toStoredProductImages, updateMerchant, uploadImage, uploadMerchantImage, validateMerchant, withToken };
|
|
1378
|
+
export { Basket, BasketFilters, BasketItem, BasketPagination, BasketReportRow, BasketSummary, Category, CategoryResponse, CombineBasketRowsParams, Consumer, ConsumerResponse, CropRect, DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, DeletableEntityKind, Employee, EmployeeResponse, EntityDefinition, EntityId, EntityInput, EntityKind, EntityTypes, ErrorMessage, Extras, FetchByIdParams, FetchCategoriesParams, FetchEmployeesParams, FetchProductsParams, FetchPromotionsParams, FetchStoresParams, FitImageOptions, ImageFitPlan, ImageRule, ImageRuleError, ImageSize, ImageTooSmallError, LookupDefinition, LookupKind, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, Merchant, MerchantColourKey, MerchantColourSet, MerchantColours, MerchantImageIds, MerchantImageSlot, MerchantImageSlotDefinition, MerchantLinkKey, MerchantLinks, MerchantPatch, MerchantResponse, MessageInfo, ParsedBasket, PrepareImageOptions, Product, ProductInstance, ProductInstanceInput, ProductInstances, ProductResponse, ProductSaveInput, Promotion, PromotionResponse, PromotionRuleSet, ReportData, ReportKey, ReportQuery, ReportQueryMap, ReportResponse, RepricedInstance, RequestOptions, ResourceDefinition, ResourceKind, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, Saved, SessionStatus, ShopwaveApiError, ShopwaveErrorMap, Store, StoreResponse, SubmitEntityArgs, SubmitEntityResponse, SuccessMessage, UPLOAD_KINDS, UPLOAD_PREFIXES, UpdateMerchantOptions, UploadImageParams, UploadKind, UploadMerchantImageOptions, UploadPrefix, UploadedImage, User, UserEmployee, UserResponse, WritableEntityKind, apiDelete, apiGet, apiRequest, apiResponse, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, checkImageRule, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProductInstanceTags, fetchProductTags, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, isUploadPrefix, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, normalizeTagList, parseAspectRatio, parseBasketReportData, planImageFit, prepareImage, productImageRole, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, toStoredProductImages, updateMerchant, uploadImage, uploadMerchantImage, validateMerchant, withToken };
|
|
1282
1379
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/core/index.d.ts
CHANGED
|
@@ -913,11 +913,12 @@ declare const SHOPWAVE_LOOKUPS: Readonly<Record<LookupKind, LookupDefinition>>;
|
|
|
913
913
|
//#endregion
|
|
914
914
|
//#region src/core/imageFit.d.ts
|
|
915
915
|
/**
|
|
916
|
-
* Browser helpers for getting an image to
|
|
916
|
+
* Browser helpers for getting an image to the right size before upload.
|
|
917
917
|
*
|
|
918
|
-
* Shopwave doesn't resize uploads,
|
|
919
|
-
*
|
|
920
|
-
*
|
|
918
|
+
* Shopwave doesn't resize uploads, so images are scaled and centre-cropped in
|
|
919
|
+
* the browser: to an exact size for the merchant image slots
|
|
920
|
+
* ({@link fitImageToSize}), or to a rule (ratio, minimum, maximum) with
|
|
921
|
+
* {@link prepareImage}, which apps use to give each kind of image its own rule.
|
|
921
922
|
*/
|
|
922
923
|
/** Source rectangle to draw so the image covers `dstWidth × dstHeight` (centre crop, no stretching). */
|
|
923
924
|
interface CropRect {
|
|
@@ -951,6 +952,102 @@ interface FitImageOptions {
|
|
|
951
952
|
* input, with the output type's extension.
|
|
952
953
|
*/
|
|
953
954
|
declare function fitImageToSize(file: Blob, width: number, height: number, options?: FitImageOptions): Promise<File>;
|
|
955
|
+
/**
|
|
956
|
+
* How an image must end up before upload. Every field is optional; give an
|
|
957
|
+
* exact size (`width` + `height`) or an `aspectRatio`, not both.
|
|
958
|
+
*
|
|
959
|
+
* Images are always scaled down first and then centre-cropped (never
|
|
960
|
+
* stretched): the kept area is the largest one with the right shape.
|
|
961
|
+
*
|
|
962
|
+
* @example
|
|
963
|
+
* // "Cropped to 100:77, at least 600 × 462", at most 2000 px on the long side
|
|
964
|
+
* { aspectRatio: "100:77", minWidth: 600, minHeight: 462, maxLongSide: 2000 }
|
|
965
|
+
* // Exactly 600 × 462
|
|
966
|
+
* { width: 600, height: 462 }
|
|
967
|
+
* // Any shape, scaled down to fit 2000 px
|
|
968
|
+
* { maxLongSide: 2000 }
|
|
969
|
+
*/
|
|
970
|
+
interface ImageRule {
|
|
971
|
+
/** Exact output width (needs `height`). */
|
|
972
|
+
width?: number;
|
|
973
|
+
/** Exact output height (needs `width`). */
|
|
974
|
+
height?: number;
|
|
975
|
+
/** Shape to crop to: `1.3`, `"100:77"`, `"100/77"` or `[100, 77]`. */
|
|
976
|
+
aspectRatio?: number | string | readonly [number, number];
|
|
977
|
+
/** Smallest acceptable output; a smaller image is refused (see `allowUpscale`). */
|
|
978
|
+
minWidth?: number;
|
|
979
|
+
minHeight?: number;
|
|
980
|
+
/** Largest output; a bigger image is scaled down to fit. */
|
|
981
|
+
maxWidth?: number;
|
|
982
|
+
maxHeight?: number;
|
|
983
|
+
/** Largest output on the longer side, whichever it is. */
|
|
984
|
+
maxLongSide?: number;
|
|
985
|
+
/** Enlarge a too-small image instead of refusing it. Default false. */
|
|
986
|
+
allowUpscale?: boolean;
|
|
987
|
+
}
|
|
988
|
+
/** What {@link prepareImage} will do to an image, worked out without touching it. */
|
|
989
|
+
interface ImageFitPlan {
|
|
990
|
+
/** The area of the source that's kept. */
|
|
991
|
+
crop: CropRect;
|
|
992
|
+
/** Output size. */
|
|
993
|
+
width: number;
|
|
994
|
+
height: number;
|
|
995
|
+
/** True when the source already fits the rule, so it can be uploaded as it is. */
|
|
996
|
+
unchanged: boolean;
|
|
997
|
+
}
|
|
998
|
+
/** A rule that can't be met by any image (a mistake in the rule, not the image). */
|
|
999
|
+
declare class ImageRuleError extends Error {
|
|
1000
|
+
constructor(message: string);
|
|
1001
|
+
}
|
|
1002
|
+
/** The image is smaller than the rule's minimum (and `allowUpscale` is off). */
|
|
1003
|
+
declare class ImageTooSmallError extends Error {
|
|
1004
|
+
/** The smallest size the rule accepts. */
|
|
1005
|
+
readonly required: ImageSize;
|
|
1006
|
+
/** The largest area of the right shape the image could give. */
|
|
1007
|
+
readonly actual: ImageSize;
|
|
1008
|
+
constructor(required: ImageSize, actual: ImageSize);
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* An aspect ratio as width ÷ height: `"100:77"`, `"100/77"`, `[100, 77]` →
|
|
1012
|
+
* 1.2987…; `1.3` → 1.3. Throws {@link ImageRuleError} for anything else.
|
|
1013
|
+
*/
|
|
1014
|
+
declare function parseAspectRatio(value: number | string | readonly [number, number]): number;
|
|
1015
|
+
/** Throws {@link ImageRuleError} when the rule contradicts itself. */
|
|
1016
|
+
declare function checkImageRule(rule: ImageRule): void;
|
|
1017
|
+
/**
|
|
1018
|
+
* Works out what to do to a `source`-sized image to meet `rule`: the centred
|
|
1019
|
+
* crop of the right shape (the largest one), then the output size (scaled
|
|
1020
|
+
* down to the maximum, never below the minimum). Pure: no browser needed.
|
|
1021
|
+
*
|
|
1022
|
+
* Throws {@link ImageTooSmallError} when the crop is below the minimum (or
|
|
1023
|
+
* the exact size) and `allowUpscale` is off, and {@link ImageRuleError} for a
|
|
1024
|
+
* contradictory rule.
|
|
1025
|
+
*
|
|
1026
|
+
* @example
|
|
1027
|
+
* planImageFit({ width: 6000, height: 4000 }, { aspectRatio: "100:77", minWidth: 600, minHeight: 462, maxLongSide: 2000 })
|
|
1028
|
+
* // → crop { sx: 403, sy: 0, sw: 5194, sh: 4000 }, 2000 × 1540
|
|
1029
|
+
*/
|
|
1030
|
+
declare function planImageFit(source: ImageSize, rule: ImageRule): ImageFitPlan;
|
|
1031
|
+
interface PrepareImageOptions {
|
|
1032
|
+
/** Output type. Default: the source's type when it's PNG, JPEG or WebP, else PNG. */
|
|
1033
|
+
type?: "image/png" | "image/jpeg" | "image/webp";
|
|
1034
|
+
/** 0–1, for JPEG and WebP. Default 0.9. */
|
|
1035
|
+
quality?: number;
|
|
1036
|
+
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Returns the image meeting `rule` ({@link planImageFit}): centre-cropped to
|
|
1039
|
+
* the right shape and scaled in a single draw. An image that already fits is
|
|
1040
|
+
* returned untouched (same bytes). Browser only.
|
|
1041
|
+
*
|
|
1042
|
+
* Throws {@link ImageTooSmallError} (show `required` and `actual` to the
|
|
1043
|
+
* person) or {@link ImageRuleError}; an unreadable file rejects with the
|
|
1044
|
+
* browser's decoding error.
|
|
1045
|
+
*
|
|
1046
|
+
* @example
|
|
1047
|
+
* const ready = await prepareImage(file, { aspectRatio: "100:77", minWidth: 600, minHeight: 462, maxLongSide: 2000 });
|
|
1048
|
+
* await uploadImage(ready, { kind: "product", prefix: "product" });
|
|
1049
|
+
*/
|
|
1050
|
+
declare function prepareImage(file: Blob, rule: ImageRule, options?: PrepareImageOptions): Promise<File>;
|
|
954
1051
|
//#endregion
|
|
955
1052
|
//#region src/core/upload.d.ts
|
|
956
1053
|
interface UploadImageParams {
|
|
@@ -1278,5 +1375,5 @@ declare function productImageRole(value: unknown): UploadPrefix | null;
|
|
|
1278
1375
|
*/
|
|
1279
1376
|
declare function toStoredProductImages(images: unknown): string[];
|
|
1280
1377
|
//#endregion
|
|
1281
|
-
export { Basket, BasketFilters, BasketItem, BasketPagination, BasketReportRow, BasketSummary, Category, CategoryResponse, CombineBasketRowsParams, Consumer, ConsumerResponse, CropRect, DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, DeletableEntityKind, Employee, EmployeeResponse, EntityDefinition, EntityId, EntityInput, EntityKind, EntityTypes, ErrorMessage, Extras, FetchByIdParams, FetchCategoriesParams, FetchEmployeesParams, FetchProductsParams, FetchPromotionsParams, FetchStoresParams, FitImageOptions, ImageSize, LookupDefinition, LookupKind, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, Merchant, MerchantColourKey, MerchantColourSet, MerchantColours, MerchantImageIds, MerchantImageSlot, MerchantImageSlotDefinition, MerchantLinkKey, MerchantLinks, MerchantPatch, MerchantResponse, MessageInfo, ParsedBasket, Product, ProductInstance, ProductInstanceInput, ProductInstances, ProductResponse, ProductSaveInput, Promotion, PromotionResponse, PromotionRuleSet, ReportData, ReportKey, ReportQuery, ReportQueryMap, ReportResponse, RepricedInstance, RequestOptions, ResourceDefinition, ResourceKind, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, Saved, SessionStatus, ShopwaveApiError, ShopwaveErrorMap, Store, StoreResponse, SubmitEntityArgs, SubmitEntityResponse, SuccessMessage, UPLOAD_KINDS, UPLOAD_PREFIXES, UpdateMerchantOptions, UploadImageParams, UploadKind, UploadMerchantImageOptions, UploadPrefix, UploadedImage, User, UserEmployee, UserResponse, WritableEntityKind, apiDelete, apiGet, apiRequest, apiResponse, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProductInstanceTags, fetchProductTags, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, isUploadPrefix, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, normalizeTagList, parseBasketReportData, productImageRole, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, toStoredProductImages, updateMerchant, uploadImage, uploadMerchantImage, validateMerchant, withToken };
|
|
1378
|
+
export { Basket, BasketFilters, BasketItem, BasketPagination, BasketReportRow, BasketSummary, Category, CategoryResponse, CombineBasketRowsParams, Consumer, ConsumerResponse, CropRect, DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, DeletableEntityKind, Employee, EmployeeResponse, EntityDefinition, EntityId, EntityInput, EntityKind, EntityTypes, ErrorMessage, Extras, FetchByIdParams, FetchCategoriesParams, FetchEmployeesParams, FetchProductsParams, FetchPromotionsParams, FetchStoresParams, FitImageOptions, ImageFitPlan, ImageRule, ImageRuleError, ImageSize, ImageTooSmallError, LookupDefinition, LookupKind, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, Merchant, MerchantColourKey, MerchantColourSet, MerchantColours, MerchantImageIds, MerchantImageSlot, MerchantImageSlotDefinition, MerchantLinkKey, MerchantLinks, MerchantPatch, MerchantResponse, MessageInfo, ParsedBasket, PrepareImageOptions, Product, ProductInstance, ProductInstanceInput, ProductInstances, ProductResponse, ProductSaveInput, Promotion, PromotionResponse, PromotionRuleSet, ReportData, ReportKey, ReportQuery, ReportQueryMap, ReportResponse, RepricedInstance, RequestOptions, ResourceDefinition, ResourceKind, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, Saved, SessionStatus, ShopwaveApiError, ShopwaveErrorMap, Store, StoreResponse, SubmitEntityArgs, SubmitEntityResponse, SuccessMessage, UPLOAD_KINDS, UPLOAD_PREFIXES, UpdateMerchantOptions, UploadImageParams, UploadKind, UploadMerchantImageOptions, UploadPrefix, UploadedImage, User, UserEmployee, UserResponse, WritableEntityKind, apiDelete, apiGet, apiRequest, apiResponse, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, checkImageRule, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProductInstanceTags, fetchProductTags, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, isUploadPrefix, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, normalizeTagList, parseAspectRatio, parseBasketReportData, planImageFit, prepareImage, productImageRole, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, toStoredProductImages, updateMerchant, uploadImage, uploadMerchantImage, validateMerchant, withToken };
|
|
1282
1379
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/core/index.js
CHANGED
|
@@ -636,6 +636,35 @@ async function readImageSize(file) {
|
|
|
636
636
|
bitmap.close?.();
|
|
637
637
|
}
|
|
638
638
|
}
|
|
639
|
+
/** Draws `crop` of the bitmap at `width × height` and encodes it (one resample). */
|
|
640
|
+
async function drawCrop(bitmap, crop, width, height, type, quality, fn) {
|
|
641
|
+
const { sx, sy, sw, sh } = crop;
|
|
642
|
+
if (typeof OffscreenCanvas === "function") {
|
|
643
|
+
const canvas$1 = new OffscreenCanvas(width, height);
|
|
644
|
+
const ctx$1 = canvas$1.getContext("2d");
|
|
645
|
+
if (!ctx$1) throw new Error(`${fn}: no 2D canvas context`);
|
|
646
|
+
ctx$1.imageSmoothingQuality = "high";
|
|
647
|
+
ctx$1.drawImage(bitmap, sx, sy, sw, sh, 0, 0, width, height);
|
|
648
|
+
return canvas$1.convertToBlob({
|
|
649
|
+
type,
|
|
650
|
+
quality
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
const canvas = document.createElement("canvas");
|
|
654
|
+
canvas.width = width;
|
|
655
|
+
canvas.height = height;
|
|
656
|
+
const ctx = canvas.getContext("2d");
|
|
657
|
+
if (!ctx) throw new Error(`${fn}: no 2D canvas context`);
|
|
658
|
+
ctx.imageSmoothingQuality = "high";
|
|
659
|
+
ctx.drawImage(bitmap, sx, sy, sw, sh, 0, 0, width, height);
|
|
660
|
+
return new Promise((resolve, reject) => canvas.toBlob((b) => b ? resolve(b) : reject(/* @__PURE__ */ new Error(`${fn}: encoding failed`)), type, quality));
|
|
661
|
+
}
|
|
662
|
+
/** The input's name with the output type's extension. */
|
|
663
|
+
function outputName(file, type) {
|
|
664
|
+
const name = file.name || "image";
|
|
665
|
+
const ext = type === "image/jpeg" ? "jpg" : type.split("/")[1];
|
|
666
|
+
return `${name.replace(/\.[^.]+$/, "")}.${ext}`;
|
|
667
|
+
}
|
|
639
668
|
/**
|
|
640
669
|
* Returns the image at exactly `width × height`: scaled and centre-cropped
|
|
641
670
|
* (never stretched). Browser only. The result is a `File` named like the
|
|
@@ -644,39 +673,194 @@ async function readImageSize(file) {
|
|
|
644
673
|
async function fitImageToSize(file, width, height, options = {}) {
|
|
645
674
|
requireBrowserImages("fitImageToSize");
|
|
646
675
|
const { type = "image/png", quality, keepIfExact = true } = options;
|
|
647
|
-
const
|
|
648
|
-
const ext = type === "image/jpeg" ? "jpg" : type.split("/")[1];
|
|
649
|
-
const outName = `${name.replace(/\.[^.]+$/, "")}.${ext}`;
|
|
676
|
+
const outName = outputName(file, type);
|
|
650
677
|
const bitmap = await createImageBitmap(file);
|
|
651
678
|
try {
|
|
652
679
|
if (keepIfExact && bitmap.width === width && bitmap.height === height && file.type === type) return file instanceof File ? file : new File([file], outName, { type });
|
|
653
|
-
const
|
|
654
|
-
let blob;
|
|
655
|
-
if (typeof OffscreenCanvas === "function") {
|
|
656
|
-
const canvas = new OffscreenCanvas(width, height);
|
|
657
|
-
const ctx = canvas.getContext("2d");
|
|
658
|
-
if (!ctx) throw new Error("fitImageToSize: no 2D canvas context");
|
|
659
|
-
ctx.imageSmoothingQuality = "high";
|
|
660
|
-
ctx.drawImage(bitmap, sx, sy, sw, sh, 0, 0, width, height);
|
|
661
|
-
blob = await canvas.convertToBlob({
|
|
662
|
-
type,
|
|
663
|
-
quality
|
|
664
|
-
});
|
|
665
|
-
} else {
|
|
666
|
-
const canvas = document.createElement("canvas");
|
|
667
|
-
canvas.width = width;
|
|
668
|
-
canvas.height = height;
|
|
669
|
-
const ctx = canvas.getContext("2d");
|
|
670
|
-
if (!ctx) throw new Error("fitImageToSize: no 2D canvas context");
|
|
671
|
-
ctx.imageSmoothingQuality = "high";
|
|
672
|
-
ctx.drawImage(bitmap, sx, sy, sw, sh, 0, 0, width, height);
|
|
673
|
-
blob = await new Promise((resolve, reject) => canvas.toBlob((b) => b ? resolve(b) : reject(/* @__PURE__ */ new Error("fitImageToSize: encoding failed")), type, quality));
|
|
674
|
-
}
|
|
680
|
+
const blob = await drawCrop(bitmap, coverCrop(bitmap.width, bitmap.height, width, height), width, height, type, quality, "fitImageToSize");
|
|
675
681
|
return new File([blob], outName, { type });
|
|
676
682
|
} finally {
|
|
677
683
|
bitmap.close?.();
|
|
678
684
|
}
|
|
679
685
|
}
|
|
686
|
+
/** A rule that can't be met by any image (a mistake in the rule, not the image). */
|
|
687
|
+
var ImageRuleError = class extends Error {
|
|
688
|
+
constructor(message) {
|
|
689
|
+
super(message);
|
|
690
|
+
this.name = "ImageRuleError";
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
/** The image is smaller than the rule's minimum (and `allowUpscale` is off). */
|
|
694
|
+
var ImageTooSmallError = class extends Error {
|
|
695
|
+
/** The smallest size the rule accepts. */
|
|
696
|
+
required;
|
|
697
|
+
/** The largest area of the right shape the image could give. */
|
|
698
|
+
actual;
|
|
699
|
+
constructor(required, actual) {
|
|
700
|
+
super(`The image is too small: it needs to be at least ${required.width} × ${required.height}, and it's ${actual.width} × ${actual.height}`);
|
|
701
|
+
this.name = "ImageTooSmallError";
|
|
702
|
+
this.required = required;
|
|
703
|
+
this.actual = actual;
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
const isPositive = (n) => typeof n === "number" && Number.isFinite(n) && n > 0;
|
|
707
|
+
/**
|
|
708
|
+
* An aspect ratio as width ÷ height: `"100:77"`, `"100/77"`, `[100, 77]` →
|
|
709
|
+
* 1.2987…; `1.3` → 1.3. Throws {@link ImageRuleError} for anything else.
|
|
710
|
+
*/
|
|
711
|
+
function parseAspectRatio(value) {
|
|
712
|
+
let parts = null;
|
|
713
|
+
if (typeof value === "number") return isPositive(value) ? value : badRatio(value);
|
|
714
|
+
if (Array.isArray(value)) parts = [value[0], value[1]];
|
|
715
|
+
else if (typeof value === "string") {
|
|
716
|
+
const text$1 = value.trim();
|
|
717
|
+
const match = /^(\d+(?:\.\d+)?)\s*[:/x×]\s*(\d+(?:\.\d+)?)$/i.exec(text$1);
|
|
718
|
+
if (match) parts = [Number(match[1]), Number(match[2])];
|
|
719
|
+
else if (/^\d+(?:\.\d+)?$/.test(text$1)) return isPositive(Number(text$1)) ? Number(text$1) : badRatio(value);
|
|
720
|
+
}
|
|
721
|
+
if (parts && isPositive(parts[0]) && isPositive(parts[1])) return parts[0] / parts[1];
|
|
722
|
+
return badRatio(value);
|
|
723
|
+
}
|
|
724
|
+
function badRatio(value) {
|
|
725
|
+
throw new ImageRuleError(`Not an aspect ratio: ${JSON.stringify(value)} (use e.g. "100:77", [100, 77] or 1.3)`);
|
|
726
|
+
}
|
|
727
|
+
/** Throws {@link ImageRuleError} when the rule contradicts itself. */
|
|
728
|
+
function checkImageRule(rule) {
|
|
729
|
+
if (!rule || typeof rule !== "object") throw new ImageRuleError("An image rule must be an object");
|
|
730
|
+
for (const key of [
|
|
731
|
+
"width",
|
|
732
|
+
"height",
|
|
733
|
+
"minWidth",
|
|
734
|
+
"minHeight",
|
|
735
|
+
"maxWidth",
|
|
736
|
+
"maxHeight",
|
|
737
|
+
"maxLongSide"
|
|
738
|
+
]) if (rule[key] != null && !isPositive(rule[key])) throw new ImageRuleError(`${key} must be a positive number`);
|
|
739
|
+
if (rule.width != null || rule.height != null) {
|
|
740
|
+
if (rule.width == null || rule.height == null) throw new ImageRuleError("An exact size needs both width and height");
|
|
741
|
+
if (rule.aspectRatio != null) throw new ImageRuleError("Give an exact size or an aspectRatio, not both (the size sets the ratio)");
|
|
742
|
+
const extra = [
|
|
743
|
+
"minWidth",
|
|
744
|
+
"minHeight",
|
|
745
|
+
"maxWidth",
|
|
746
|
+
"maxHeight",
|
|
747
|
+
"maxLongSide"
|
|
748
|
+
].filter((key) => rule[key] != null);
|
|
749
|
+
if (extra.length > 0) throw new ImageRuleError(`An exact size is already the minimum and the maximum; remove ${extra.join(", ")}`);
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
if (rule.aspectRatio != null) parseAspectRatio(rule.aspectRatio);
|
|
753
|
+
if (rule.minWidth != null && rule.maxWidth != null && rule.minWidth > rule.maxWidth) throw new ImageRuleError("minWidth is larger than maxWidth");
|
|
754
|
+
if (rule.minHeight != null && rule.maxHeight != null && rule.minHeight > rule.maxHeight) throw new ImageRuleError("minHeight is larger than maxHeight");
|
|
755
|
+
if (rule.maxLongSide != null && Math.max(rule.minWidth ?? 0, rule.minHeight ?? 0) > rule.maxLongSide) throw new ImageRuleError("The minimum size is larger than maxLongSide");
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Works out what to do to a `source`-sized image to meet `rule`: the centred
|
|
759
|
+
* crop of the right shape (the largest one), then the output size (scaled
|
|
760
|
+
* down to the maximum, never below the minimum). Pure: no browser needed.
|
|
761
|
+
*
|
|
762
|
+
* Throws {@link ImageTooSmallError} when the crop is below the minimum (or
|
|
763
|
+
* the exact size) and `allowUpscale` is off, and {@link ImageRuleError} for a
|
|
764
|
+
* contradictory rule.
|
|
765
|
+
*
|
|
766
|
+
* @example
|
|
767
|
+
* planImageFit({ width: 6000, height: 4000 }, { aspectRatio: "100:77", minWidth: 600, minHeight: 462, maxLongSide: 2000 })
|
|
768
|
+
* // → crop { sx: 403, sy: 0, sw: 5194, sh: 4000 }, 2000 × 1540
|
|
769
|
+
*/
|
|
770
|
+
function planImageFit(source, rule) {
|
|
771
|
+
checkImageRule(rule);
|
|
772
|
+
const { width: W, height: H } = source ?? {};
|
|
773
|
+
if (!isPositive(W) || !isPositive(H)) throw new Error("planImageFit: the image has no size");
|
|
774
|
+
const exact = rule.width != null && rule.height != null;
|
|
775
|
+
const ratio = exact ? rule.width / rule.height : rule.aspectRatio != null ? parseAspectRatio(rule.aspectRatio) : null;
|
|
776
|
+
const crop = ratio == null ? {
|
|
777
|
+
sx: 0,
|
|
778
|
+
sy: 0,
|
|
779
|
+
sw: W,
|
|
780
|
+
sh: H
|
|
781
|
+
} : coverCrop(W, H, ratio, 1);
|
|
782
|
+
const { sw, sh } = crop;
|
|
783
|
+
const kept = {
|
|
784
|
+
width: sw,
|
|
785
|
+
height: sh
|
|
786
|
+
};
|
|
787
|
+
let width;
|
|
788
|
+
let height;
|
|
789
|
+
if (exact) {
|
|
790
|
+
width = rule.width;
|
|
791
|
+
height = rule.height;
|
|
792
|
+
if ((sw < width || sh < height) && !rule.allowUpscale) throw new ImageTooSmallError({
|
|
793
|
+
width,
|
|
794
|
+
height
|
|
795
|
+
}, kept);
|
|
796
|
+
} else {
|
|
797
|
+
const minW = rule.minWidth ?? 0;
|
|
798
|
+
const minH = rule.minHeight ?? 0;
|
|
799
|
+
if ((sw < minW || sh < minH) && !rule.allowUpscale) throw new ImageTooSmallError(requiredSize(minW, minH, ratio), kept);
|
|
800
|
+
let scale = 1;
|
|
801
|
+
if (rule.maxWidth != null) scale = Math.min(scale, rule.maxWidth / sw);
|
|
802
|
+
if (rule.maxHeight != null) scale = Math.min(scale, rule.maxHeight / sh);
|
|
803
|
+
if (rule.maxLongSide != null) scale = Math.min(scale, rule.maxLongSide / Math.max(sw, sh));
|
|
804
|
+
scale = Math.max(scale, minW / sw, minH / sh);
|
|
805
|
+
width = Math.max(1, Math.round(sw * scale));
|
|
806
|
+
height = Math.max(1, Math.round(sh * scale));
|
|
807
|
+
}
|
|
808
|
+
const unchanged = crop.sx === 0 && crop.sy === 0 && sw === W && sh === H && width === W && height === H;
|
|
809
|
+
return {
|
|
810
|
+
crop,
|
|
811
|
+
width,
|
|
812
|
+
height,
|
|
813
|
+
unchanged
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
/** The minimum as a full size: a ratio rule with only one minimum implies the other. */
|
|
817
|
+
function requiredSize(minW, minH, ratio) {
|
|
818
|
+
if (ratio == null) return {
|
|
819
|
+
width: minW,
|
|
820
|
+
height: minH
|
|
821
|
+
};
|
|
822
|
+
return {
|
|
823
|
+
width: Math.max(minW, Math.ceil(minH * ratio)),
|
|
824
|
+
height: Math.max(minH, Math.ceil(minW / ratio))
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
const OUTPUT_TYPES = [
|
|
828
|
+
"image/png",
|
|
829
|
+
"image/jpeg",
|
|
830
|
+
"image/webp"
|
|
831
|
+
];
|
|
832
|
+
/**
|
|
833
|
+
* Returns the image meeting `rule` ({@link planImageFit}): centre-cropped to
|
|
834
|
+
* the right shape and scaled in a single draw. An image that already fits is
|
|
835
|
+
* returned untouched (same bytes). Browser only.
|
|
836
|
+
*
|
|
837
|
+
* Throws {@link ImageTooSmallError} (show `required` and `actual` to the
|
|
838
|
+
* person) or {@link ImageRuleError}; an unreadable file rejects with the
|
|
839
|
+
* browser's decoding error.
|
|
840
|
+
*
|
|
841
|
+
* @example
|
|
842
|
+
* const ready = await prepareImage(file, { aspectRatio: "100:77", minWidth: 600, minHeight: 462, maxLongSide: 2000 });
|
|
843
|
+
* await uploadImage(ready, { kind: "product", prefix: "product" });
|
|
844
|
+
*/
|
|
845
|
+
async function prepareImage(file, rule, options = {}) {
|
|
846
|
+
checkImageRule(rule);
|
|
847
|
+
requireBrowserImages("prepareImage");
|
|
848
|
+
const sourceType = file.type && OUTPUT_TYPES.includes(file.type) ? file.type : "image/png";
|
|
849
|
+
const type = options.type ?? sourceType;
|
|
850
|
+
const quality = options.quality ?? (type === "image/png" ? void 0 : .9);
|
|
851
|
+
const bitmap = await createImageBitmap(file);
|
|
852
|
+
try {
|
|
853
|
+
const plan = planImageFit({
|
|
854
|
+
width: bitmap.width,
|
|
855
|
+
height: bitmap.height
|
|
856
|
+
}, rule);
|
|
857
|
+
if (plan.unchanged && type === file.type) return file instanceof File ? file : new File([file], outputName(file, type), { type });
|
|
858
|
+
const blob = await drawCrop(bitmap, plan.crop, plan.width, plan.height, type, quality, "prepareImage");
|
|
859
|
+
return new File([blob], outputName(file, type), { type });
|
|
860
|
+
} finally {
|
|
861
|
+
bitmap.close?.();
|
|
862
|
+
}
|
|
863
|
+
}
|
|
680
864
|
|
|
681
865
|
//#endregion
|
|
682
866
|
//#region src/core/upload.ts
|
|
@@ -1403,5 +1587,5 @@ async function fetchUser(options = {}) {
|
|
|
1403
1587
|
}
|
|
1404
1588
|
|
|
1405
1589
|
//#endregion
|
|
1406
|
-
export { DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, PromotionRuleSet, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, ShopwaveApiError, UPLOAD_KINDS, UPLOAD_PREFIXES, apiDelete, apiGet, apiRequest, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProductInstanceTags, fetchProductTags, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, isUploadPrefix, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, normalizeTagList, parseBasketReportData, productImageRole, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, toStoredProductImages, updateMerchant, uploadImage, uploadMerchantImage, validateMerchant, withToken };
|
|
1590
|
+
export { DEFAULT_BASKET_FILTERS, DEFAULT_PAGINATION, ImageRuleError, ImageTooSmallError, MERCHANT_COLOUR_KEYS, MERCHANT_FIELD_MAX_LENGTH, MERCHANT_IMAGE_SLOTS, MERCHANT_IMAGE_SLOT_KEYS, MERCHANT_LINK_KEYS, MERCHANT_LINK_PATHS, MERCHANT_OBJECT_FIELDS, MERCHANT_READ_ONLY_FIELDS, PromotionRuleSet, SHOPWAVE_ENTITIES, SHOPWAVE_IMAGE_BASE_URL, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, SHOPWAVE_UPLOAD, ShopwaveApiError, UPLOAD_KINDS, UPLOAD_PREFIXES, apiDelete, apiGet, apiRequest, apiSend, assertNoApiErrors, authorizationFor, buildBasketReportQuery, buildConsumerMap, checkImageRule, collectConsumerIds, collectProductIds, combineBasketRows, computeBasketSummary, coverCrop, deleteCategory, deleteEmployee, deleteEntity, deleteEntityById, deleteProduct, deletePromotion, deleteStore, fetchCategories, fetchCategory, fetchConsumer, fetchConsumers, fetchEmployee, fetchEmployees, fetchEntityById, fetchMerchant, fetchProduct, fetchProductInstanceTags, fetchProductTags, fetchProducts, fetchProductsMap, fetchPromotion, fetchPromotions, fetchReport, fetchSession, fetchStore, fetchStores, fetchUser, findRepricedInstances, fitImageToSize, formatDateForQuery, getApiErrorMap, getApiErrors, getImageUrl, getMerchantImage, getMerchantImageUrl, imageFileName, isSameInstancePrice, isUploadKind, isUploadPrefix, loginPath, logout, logoutPath, merchantLinksFromForm, merchantLinksToForm, normalizeMerchantLinks, normalizeTagList, parseAspectRatio, parseBasketReportData, planImageFit, prepareImage, productImageRole, readImageSize, rolesById, saveCategory, saveEmployee, saveEntities, saveEntity, saveProduct, savePromotion, saveStore, setMerchantImage, submitEntity, toProductInstancesForSave, toShopwaveApiError, toStoredImageIds, toStoredProductImages, updateMerchant, uploadImage, uploadMerchantImage, validateMerchant, withToken };
|
|
1407
1591
|
//# sourceMappingURL=index.js.map
|