@hellkite/pipkin 0.5.0 → 0.5.1

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.
Files changed (85) hide show
  1. package/build/src/lib/bundler.d.ts +1 -2
  2. package/build/src/lib/bundler.js.map +1 -1
  3. package/build/src/lib/replacement.d.ts +1 -2
  4. package/build/src/lib/replacement.js.map +1 -1
  5. package/build/src/lib/template.d.ts +9 -12
  6. package/build/src/lib/template.js +62 -30
  7. package/build/src/lib/template.js.map +1 -1
  8. package/build/src/lib/types/2d.d.ts +4 -5
  9. package/build/src/lib/types/boundingBox.d.ts +19 -0
  10. package/build/src/lib/types/boundingBox.js +3 -0
  11. package/build/src/lib/types/boundingBox.js.map +1 -0
  12. package/build/src/lib/types/containers.d.ts +7 -10
  13. package/build/src/lib/types/containers.js +0 -1
  14. package/build/src/lib/types/containers.js.map +1 -1
  15. package/build/src/lib/types/css.d.ts +4 -1
  16. package/build/src/lib/types/css.js +6 -3
  17. package/build/src/lib/types/css.js.map +1 -1
  18. package/build/src/lib/types/image.d.ts +17 -31
  19. package/build/src/lib/types/image.js +6 -2
  20. package/build/src/lib/types/image.js.map +1 -1
  21. package/build/src/lib/types/index.d.ts +2 -2
  22. package/build/src/lib/types/index.js +2 -2
  23. package/build/src/lib/types/index.js.map +1 -1
  24. package/build/src/lib/types/position.d.ts +21 -0
  25. package/build/src/lib/types/position.js +42 -0
  26. package/build/src/lib/types/position.js.map +1 -0
  27. package/build/src/lib/types/scale.d.ts +9 -1
  28. package/build/src/lib/types/scale.js +2 -0
  29. package/build/src/lib/types/scale.js.map +1 -1
  30. package/build/src/lib/types/size.d.ts +4 -0
  31. package/build/src/lib/types/size.js +3 -0
  32. package/build/src/lib/types/size.js.map +1 -0
  33. package/build/src/lib/types/text.d.ts +6 -6
  34. package/build/src/lib/types/text.js.map +1 -1
  35. package/build/src/lib/utils/buildFontString.d.ts +1 -1
  36. package/build/src/lib/utils/canvasToImage.d.ts +1 -1
  37. package/build/src/lib/utils/container.d.ts +3 -4
  38. package/build/src/lib/utils/container.js +14 -45
  39. package/build/src/lib/utils/container.js.map +1 -1
  40. package/build/src/lib/utils/drawBoundingBox.d.ts +1 -2
  41. package/build/src/lib/utils/drawBoundingBox.js +7 -47
  42. package/build/src/lib/utils/drawBoundingBox.js.map +1 -1
  43. package/build/src/lib/utils/htmlToImage.d.ts +3 -0
  44. package/build/src/lib/utils/htmlToImage.js +36 -0
  45. package/build/src/lib/utils/htmlToImage.js.map +1 -0
  46. package/build/src/lib/utils/index.d.ts +2 -1
  47. package/build/src/lib/utils/index.js +2 -1
  48. package/build/src/lib/utils/index.js.map +1 -1
  49. package/build/src/lib/utils/placeImage.d.ts +8 -4
  50. package/build/src/lib/utils/placeImage.js +28 -33
  51. package/build/src/lib/utils/placeImage.js.map +1 -1
  52. package/build/src/lib/utils/renderText.d.ts +2 -2
  53. package/build/src/lib/utils/renderText.js +6 -31
  54. package/build/src/lib/utils/renderText.js.map +1 -1
  55. package/build/src/lib/utils/toPx.d.ts +3 -0
  56. package/build/src/lib/utils/toPx.js +12 -0
  57. package/build/src/lib/utils/toPx.js.map +1 -0
  58. package/build/src/lib/utils/vNodeToImage.d.ts +4 -0
  59. package/build/src/lib/utils/vNodeToImage.js +36 -0
  60. package/build/src/lib/utils/vNodeToImage.js.map +1 -0
  61. package/build/src/test.js +42 -65
  62. package/build/src/test.js.map +1 -1
  63. package/package.json +3 -3
  64. package/src/lib/bundler.ts +1 -2
  65. package/src/lib/replacement.ts +1 -2
  66. package/src/lib/template.ts +83 -59
  67. package/src/lib/types/boundingBox.ts +28 -0
  68. package/src/lib/types/containers.ts +13 -24
  69. package/src/lib/types/css.ts +32 -1
  70. package/src/lib/types/image.ts +28 -45
  71. package/src/lib/types/index.ts +2 -2
  72. package/src/lib/types/scale.ts +11 -0
  73. package/src/lib/types/size.ts +4 -0
  74. package/src/lib/types/text.ts +4 -8
  75. package/src/lib/utils/buildFontString.ts +1 -1
  76. package/src/lib/utils/container.ts +25 -57
  77. package/src/lib/utils/drawBoundingBox.ts +16 -16
  78. package/src/lib/utils/htmlToImage.ts +24 -0
  79. package/src/lib/utils/index.ts +2 -1
  80. package/src/lib/utils/placeImage.ts +52 -53
  81. package/src/lib/utils/renderText.ts +8 -25
  82. package/src/lib/utils/toPx.ts +11 -0
  83. package/src/lib/types/2d.ts +0 -11
  84. package/src/lib/types/omitArgument.ts +0 -17
  85. package/src/lib/utils/canvasToImage.ts +0 -19
@@ -0,0 +1,4 @@
1
+ export type Size = {
2
+ width: number;
3
+ height: number;
4
+ };
@@ -1,11 +1,9 @@
1
- import { BoundingBox } from './2d';
2
1
  import { ReplacementMap } from './replacement';
3
2
 
4
- export type TextLayerProps<EntryType> = {
5
- key: keyof EntryType;
6
- position: TextPosition;
7
- options?: TextLayerOptions;
8
- };
3
+ export type TextRef<EntryType> =
4
+ | { key: string }
5
+ | { text: string }
6
+ | { textFn: (entry: EntryType) => string };
9
7
 
10
8
  export type TextLayerOptions = {
11
9
  font?: {
@@ -58,8 +56,6 @@ export type TextLayerOptions = {
58
56
  | 'justify-right';
59
57
  };
60
58
 
61
- export type TextPosition = BoundingBox;
62
-
63
59
  // TODO: all required
64
60
  export const DEFAULT_TEXT_LAYER_OPTIONS: TextLayerOptions = {
65
61
  xAlign: 'center',
@@ -1,4 +1,4 @@
1
- import { TextLayerOptions } from "../types/text";
1
+ import { TextLayerOptions } from "../types";
2
2
 
3
3
  export const buildFontString = (
4
4
  font: TextLayerOptions['font'],
@@ -1,52 +1,48 @@
1
- import { BoundingBox, Point } from '../types/2d';
2
- import {
3
- DEFAULT_CONTAINER_OPTIONS,
4
- DEFAULT_DIRECTION_CONTAINER_OPTIONS,
5
- DirectionContainerOptions,
6
- PackingFn,
7
- } from '../types/containers';
8
- import { ImageType, ScaleMode } from '../types/image';
9
- import { h, create as createElement, VNode } from 'virtual-dom';
10
- import nodeHtmlToImage from 'node-html-to-image';
11
- import { Jimp } from 'jimp';
12
- import { toPx } from '../types';
1
+
2
+ import { h } from 'virtual-dom';
3
+ import { DEFAULT_DIRECTION_CONTAINER_OPTIONS, DirectionContainerOptions, ImageType, PackingFn, BoundingBox, SCALE_MODE_TO_OBJECT_FIT, Size } from '../types';
4
+ import { boundingBoxToPx, toPx } from './toPx';
5
+ import merge from 'lodash.merge';
6
+ import { htmlToImage } from './htmlToImage';
13
7
 
14
8
  export const vboxPackingFn =
15
- (position: BoundingBox, options?: DirectionContainerOptions): PackingFn =>
9
+ (box: BoundingBox, options?: DirectionContainerOptions): PackingFn =>
16
10
  (background: ImageType, images: Array<ImageType>) =>
17
11
  directionalPackingFn({
18
12
  isVertical: true,
19
- background,
13
+ backgroundSize: background,
20
14
  images,
21
- position,
15
+ box,
22
16
  options,
23
17
  });
24
18
 
25
19
  export const hboxPackingFn =
26
- (position: BoundingBox, options?: DirectionContainerOptions): PackingFn =>
20
+ (box: BoundingBox, options?: DirectionContainerOptions): PackingFn =>
27
21
  (background: ImageType, images: Array<ImageType>) =>
28
22
  directionalPackingFn({
29
23
  isVertical: false,
30
- background,
24
+ backgroundSize: background,
31
25
  images,
32
- position,
26
+ box,
33
27
  options,
34
28
  });
35
29
 
36
30
  const directionalPackingFn = async ({
37
31
  isVertical,
38
- background,
32
+ backgroundSize: background,
39
33
  images,
40
- position,
34
+ box,
41
35
  options,
42
36
  }: {
43
37
  isVertical: boolean;
44
- background: ImageType;
38
+ backgroundSize: Size;
45
39
  images: Array<ImageType>;
46
- position: BoundingBox;
40
+ box: BoundingBox;
47
41
  options?: DirectionContainerOptions;
48
42
  }): Promise<ImageType> => {
49
- const objectFit = SCALE_MODE_TO_OBJECT_FIT[options?.scale ?? 'none'];
43
+ const mergedOptions = merge(DEFAULT_DIRECTION_CONTAINER_OPTIONS, options);
44
+ const objectFit = SCALE_MODE_TO_OBJECT_FIT[mergedOptions.scale];
45
+
50
46
  const children = await Promise.all(
51
47
  images.map(async image => {
52
48
  const imageBase64 = await image.getBase64('image/png');
@@ -75,44 +71,16 @@ const directionalPackingFn = async ({
75
71
  position: 'absolute',
76
72
  scale: 1,
77
73
 
78
- flexDirection: `${isVertical ? 'column' : 'row'}${options?.reversed ? '-reversed' : ''}`,
79
- gap: toPx(options?.gap ?? 0),
80
- // TODO: merge options and defaults
81
- justifyContent:
82
- options?.justifyContent ??
83
- DEFAULT_DIRECTION_CONTAINER_OPTIONS.justifyContent,
84
- alignItems:
85
- options?.alignItems ??
86
- DEFAULT_DIRECTION_CONTAINER_OPTIONS.alignItems,
74
+ flexDirection: `${isVertical ? 'column' : 'row'}${mergedOptions.reversed ? '-reversed' : ''}`,
75
+ gap: toPx(mergedOptions.gap),
76
+ justifyContent: mergedOptions.justifyContent,
77
+ alignItems: mergedOptions.alignItems,
87
78
 
88
- top: toPx(position.y),
89
- left: toPx(position.x),
90
- height: toPx(position.height),
91
- width: toPx(position.width),
79
+ ...boundingBoxToPx(box),
92
80
  },
93
81
  },
94
82
  children,
95
83
  );
96
84
 
97
- const rootNode = createElement(document);
98
- // TODO: extract this in a dif function
99
- const image = await nodeHtmlToImage({
100
- html: rootNode.toString(),
101
- transparent: true,
102
- type: 'png',
103
- puppeteerArgs: {
104
- defaultViewport: {
105
- width: background.width,
106
- height: background.height,
107
- },
108
- },
109
- });
110
- return Jimp.read(image as Buffer) as Promise<ImageType>;
111
- };
112
-
113
-
114
- const SCALE_MODE_TO_OBJECT_FIT: Record<ScaleMode, string> = {
115
- 'keep-ratio': 'contain',
116
- stretch: 'fill',
117
- none: 'none',
85
+ return htmlToImage(document, background);
118
86
  };
@@ -1,22 +1,22 @@
1
- import { canvasToImage } from './canvasToImage';
2
- import { BoundingBox, Size } from '../types/2d';
3
- import * as fabric from 'fabric/node';
4
- import { ImageType } from '../types/image';
1
+ import { h } from 'virtual-dom';
2
+ import { htmlToImage } from './htmlToImage';
3
+ import { boundingBoxToPx } from './toPx';
4
+ import { ImageType, Size, BoundingBox } from '../types';
5
5
 
6
6
  export const drawBoundingBox = async (
7
7
  box: BoundingBox,
8
+
8
9
  imageSize: Size,
9
10
  ): Promise<ImageType> => {
10
- const fabricCanvas = new fabric.Canvas(undefined, imageSize);
11
- const boundingBox = new fabric.Rect({
12
- left: box.x,
13
- top: box.y,
14
- width: box.width,
15
- height: box.height,
16
- stroke: 'red',
17
- strokeWidth: 2,
18
- fill: 'transparent',
19
- });
20
- fabricCanvas.add(boundingBox);
21
- return canvasToImage(fabricCanvas);
11
+ const document = h('div', {
12
+ style: {
13
+ position: 'absolute',
14
+ border: '2px solid red',
15
+ background: 'transparent',
16
+ boxSizing: 'border-box',
17
+ ...boundingBoxToPx(box),
18
+ },
19
+ }, []);
20
+
21
+ return htmlToImage(document, imageSize);
22
22
  };
@@ -0,0 +1,24 @@
1
+ import { create as createElement, VNode } from 'virtual-dom';
2
+ import nodeHtmlToImage from 'node-html-to-image';
3
+ import { Jimp } from 'jimp';
4
+ import { ImageType, Size } from '../types';
5
+
6
+ export const htmlToImage = async (
7
+ document: VNode,
8
+ backgroundSize: Size,
9
+ ): Promise<ImageType> => {
10
+ const html = createElement(document).toString();
11
+ // TODO: extract this in a dif function
12
+ const image = await nodeHtmlToImage({
13
+ html,
14
+ transparent: true,
15
+ type: 'png',
16
+ puppeteerArgs: {
17
+ defaultViewport: {
18
+ width: backgroundSize.width,
19
+ height: backgroundSize.height,
20
+ },
21
+ },
22
+ });
23
+ return Jimp.read(image as Buffer) as Promise<ImageType>;
24
+ };
@@ -1,6 +1,7 @@
1
1
  export * from './buildFontString';
2
- export * from './canvasToImage';
3
2
  export * from './container';
4
3
  export * from './drawBoundingBox';
5
4
  export * from './placeImage';
6
5
  export * from './renderText';
6
+ export * from './htmlToImage';
7
+ export * from './toPx';
@@ -1,65 +1,64 @@
1
- import { Jimp } from 'jimp';
2
- import path from 'path';
1
+ import { h } from 'virtual-dom';
2
+ import { boundingBoxToPx } from './toPx';
3
3
  import {
4
- Alignment,
5
- ImageType,
6
- ImagePosition,
4
+ DEFAULT_IMAGE_LAYER_OPTIONS,
7
5
  ImageLayerOptions,
8
- DEFAULT_IMAGE_ALIGNMENT,
9
- DEFAULT_SCALE_MODE,
10
- } from '../types/image';
11
-
12
- function computeOffsetFromAlignment(
13
- alignment: Alignment,
14
- size: number,
15
- boxSize: number,
16
- ): number {
17
- if (alignment === 'start') {
18
- return 0;
19
- } else if (alignment === 'center') {
20
- return Math.floor((boxSize - size) / 2);
21
- } else {
22
- return -(boxSize - size);
23
- }
24
- }
6
+ ImageType,
7
+ BoundingBox,
8
+ SCALE_MODE_TO_OBJECT_FIT,
9
+ } from '../types';
10
+ import merge from 'lodash.merge';
11
+ import { htmlToImage } from './htmlToImage';
25
12
 
26
13
  type PlaceImageProps = {
27
- background: ImageType;
28
14
  image: ImageType;
29
- position: ImagePosition;
15
+ box: BoundingBox;
16
+ backgroundSize: { width: number; height: number };
17
+ options: ImageLayerOptions;
30
18
  };
31
19
 
32
- export async function placeImage(
33
- // TODO: pass background size only
34
- { background, image, position }: PlaceImageProps,
35
- ): Promise<ImageType> {
36
- // handle alignment inside the bounding box
37
- const xAlignment =
38
- position.xAlignment ?? position.alignment ?? DEFAULT_IMAGE_ALIGNMENT;
39
- const yAlignment =
40
- position.yAlignment ?? position.alignment ?? DEFAULT_IMAGE_ALIGNMENT;
41
-
42
- const scale = position.scale ?? DEFAULT_SCALE_MODE;
20
+ export async function placeImage({
21
+ image,
22
+ box,
23
+ backgroundSize,
24
+ options,
25
+ }: PlaceImageProps): Promise<ImageType> {
26
+ const imageBase64 = await image.getBase64('image/png');
27
+ const mergedOptions = merge(DEFAULT_IMAGE_LAYER_OPTIONS, options);
28
+ const objectFit = SCALE_MODE_TO_OBJECT_FIT[mergedOptions.scale];
43
29
 
44
- if (scale === 'keep-ratio') {
45
- // TODO: handle case when box has a size equal to 0
46
- const ratio = Math.min(
47
- position.width / image.width,
48
- position.height / image.height,
49
- );
50
- image.scale(ratio);
51
- }
30
+ const document = h(
31
+ 'div',
32
+ {
33
+ style: {
34
+ display: 'flex',
35
+ position: 'absolute',
36
+ scale: 1,
52
37
 
53
- if (scale === 'stretch') {
54
- image.scaleToFit({ w: position.width, h: position.height });
55
- }
38
+ justifyContent: mergedOptions.justifyContent,
39
+ alignItems: mergedOptions.alignItems,
56
40
 
57
- const xOffset =
58
- position.x +
59
- computeOffsetFromAlignment(xAlignment, image.width, position.width);
60
- const yOffset =
61
- position.y +
62
- computeOffsetFromAlignment(yAlignment, image.height, position.height);
41
+ ...boundingBoxToPx(box),
42
+ },
43
+ },
44
+ [
45
+ h(
46
+ 'img',
47
+ {
48
+ style: {
49
+ objectFit,
50
+ flex: '1 1 auto',
51
+ minWidth: 0,
52
+ minHeight: 0,
53
+ maxWidth: '100%',
54
+ maxHeight: '100%',
55
+ },
56
+ src: imageBase64,
57
+ },
58
+ [],
59
+ ),
60
+ ],
61
+ );
63
62
 
64
- return background.composite(image, xOffset, yOffset);
63
+ return htmlToImage(document, backgroundSize);
65
64
  }
@@ -1,19 +1,17 @@
1
- import { h, create as createElement, VNode } from 'virtual-dom';
1
+ import { h, VNode } from 'virtual-dom';
2
2
  import {
3
3
  DEFAULT_TEXT_LAYER_OPTIONS,
4
4
  ImageType,
5
+ BoundingBox,
5
6
  Size,
6
7
  TextLayerOptions,
7
- TextPosition,
8
- toPx,
9
8
  } from '../types';
10
- import nodeHtmlToImage from 'node-html-to-image';
11
- import { Jimp } from 'jimp';
12
-
9
+ import { boundingBoxToPx, toPx } from './toPx';
10
+ import { htmlToImage } from './htmlToImage';
13
11
 
14
12
  export const renderText = async (
15
13
  text: string,
16
- position: TextPosition,
14
+ box: BoundingBox,
17
15
  backgroundSize: Size,
18
16
  options?: TextLayerOptions,
19
17
  ): Promise<ImageType> => {
@@ -62,15 +60,12 @@ export const renderText = async (
62
60
  overflow: 'visible',
63
61
  position: 'absolute',
64
62
 
65
- top: toPx(position.y),
66
- left: toPx(position.x),
67
- height: toPx(position.height),
68
- width: toPx(position.width),
69
-
70
63
  justifyContent:
71
64
  options?.xAlign ?? DEFAULT_TEXT_LAYER_OPTIONS.xAlign,
72
65
  alignItems:
73
66
  options?.yAlign ?? DEFAULT_TEXT_LAYER_OPTIONS.yAlign,
67
+
68
+ ...boundingBoxToPx(box),
74
69
  },
75
70
  },
76
71
  [
@@ -94,17 +89,5 @@ export const renderText = async (
94
89
  ],
95
90
  );
96
91
 
97
- const rootNode = createElement(document);
98
- const image = await nodeHtmlToImage({
99
- html: rootNode.toString(),
100
- transparent: true,
101
- type: 'png',
102
- puppeteerArgs: {
103
- defaultViewport: {
104
- width: backgroundSize.width,
105
- height: backgroundSize.height,
106
- },
107
- },
108
- });
109
- return Jimp.read(image as Buffer) as Promise<ImageType>;
92
+ return htmlToImage(document, backgroundSize);
110
93
  };
@@ -0,0 +1,11 @@
1
+ import { BoundingBox } from '../types';
2
+
3
+ export const toPx = (value: number): string => `${value}px`;
4
+
5
+ export const boundingBoxToPx = (
6
+ boundingBox: BoundingBox,
7
+ ): Record<string, string> => {
8
+ return Object.entries(boundingBox)
9
+ .map(([key, value]) => [key, toPx(value)])
10
+ .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {});
11
+ };
@@ -1,11 +0,0 @@
1
- export type Point = {
2
- x: number;
3
- y: number;
4
- };
5
-
6
- export type Size = {
7
- width: number;
8
- height: number;
9
- };
10
-
11
- export type BoundingBox = Point & Size;
@@ -1,17 +0,0 @@
1
- export type OmitArgument<
2
- T extends (...args: any[]) => any,
3
- K extends number,
4
- > = T extends (...args: infer P) => infer R
5
- ? (...args: TupleFilter<P, K>) => R
6
- : never;
7
-
8
- // Helper type to remove an argument at index K
9
- type TupleFilter<
10
- T extends any[],
11
- K extends number,
12
- I extends any[] = [],
13
- > = T extends [infer First, ...infer Rest]
14
- ? I['length'] extends K
15
- ? [...I, ...Rest] // Skip the K-th element
16
- : TupleFilter<Rest, K, [...I, First]>
17
- : I;
@@ -1,19 +0,0 @@
1
- import { Jimp } from 'jimp';
2
- import { ImageType } from '../types/image';
3
- import * as fabric from 'fabric/node';
4
-
5
- export const canvasToImage = async (canvas: fabric.Canvas): Promise<ImageType> => {
6
- const dataUrl = canvas.toDataURL({
7
- format: 'png',
8
- quality: 1,
9
- multiplier: 1,
10
- });
11
- const image = await Jimp.read(
12
- Buffer.from(dataUrl.split(',')[1], 'base64'),
13
- );
14
- return Jimp.fromBitmap({
15
- data: image.bitmap.data,
16
- width: image.bitmap.width,
17
- height: image.bitmap.height
18
- });
19
- };