-
Notifications
You must be signed in to change notification settings - Fork 659
/
crop.js
130 lines (97 loc) · 3.67 KB
/
crop.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import { copyImagePart } from './utils';
import limitNumber from '../utils/limit-number';
import { deleteFile } from '../utils/promisified-functions';
import { InvalidElementScreenshotDimensionsError } from '../errors/test-run/';
import {
MARK_LENGTH,
MARK_RIGHT_MARGIN,
MARK_BYTES_PER_PIXEL,
} from './constants';
const MARK_SEED_ERROR_THRESHOLD = 10;
const WHITE_COLOR_PART = 255;
const BLACK_COLOR_PART = 0;
export function markSeedToId (markSeed) {
let id = 0;
for (let i = 0; i < MARK_LENGTH; i++)
id = id * 2 + (markSeed[i * MARK_BYTES_PER_PIXEL] ? 1 : 0);
return id;
}
function getCorrectedColorPart (colorPart) {
const isWhite = colorPart > WHITE_COLOR_PART - MARK_SEED_ERROR_THRESHOLD;
const isBlack = colorPart < MARK_SEED_ERROR_THRESHOLD;
if (isBlack)
return BLACK_COLOR_PART;
if (isWhite)
return WHITE_COLOR_PART;
return colorPart;
}
async function validateClipInfo (clipInfo, path) {
const clipWidth = clipInfo.clipRight - clipInfo.clipLeft;
const clipHeight = clipInfo.clipBottom - clipInfo.clipTop;
if (clipWidth <= 0 || clipHeight <= 0) {
await deleteFile(path);
throw new InvalidElementScreenshotDimensionsError(clipWidth, clipHeight);
}
}
export function calculateMarkPosition (pngImage, markSeed) {
const mark = Buffer.from(markSeed);
const filtImg = Buffer.from(pngImage.data);
for (let i = 0; i < filtImg.length; i++)
filtImg[i] = getCorrectedColorPart(filtImg[i]);
const markIndex = filtImg.indexOf(mark);
if (markIndex < 0)
return null;
const endPosition = markIndex / MARK_BYTES_PER_PIXEL + MARK_LENGTH + MARK_RIGHT_MARGIN;
const x = endPosition % pngImage.width || pngImage.width;
const y = (endPosition - x) / pngImage.width + 1;
return { x, y };
}
export function getClipInfoByMarkPosition (markPosition, { width, height }) {
const { x, y } = markPosition;
const clipRight = x;
const clipBottom = y;
const clipLeft = clipRight - width;
const clipTop = clipBottom - height;
return {
clipLeft,
clipTop,
clipRight,
clipBottom,
};
}
export function getClipInfoByCropDimensions ({ clipRight, clipLeft, clipBottom, clipTop }, cropDimensions) {
if (cropDimensions) {
const { right, top, bottom, left } = cropDimensions;
clipRight = limitNumber(clipLeft + right, clipLeft, clipRight);
clipBottom = limitNumber(clipTop + bottom, clipTop, clipBottom);
clipLeft = limitNumber(clipLeft + left, clipLeft, clipRight);
clipTop = limitNumber(clipTop + top, clipTop, clipBottom);
}
return {
clipLeft,
clipTop,
clipRight,
clipBottom,
};
}
export function calculateClipInfo (pngImage, markSeedPosition, clientAreaDimensions, cropDimensions) {
let clipInfo = {
clipRight: pngImage.width,
clipBottom: pngImage.height,
clipLeft: 0,
clipTop: 0,
};
if (markSeedPosition && clientAreaDimensions)
clipInfo = getClipInfoByMarkPosition(markSeedPosition, clientAreaDimensions);
clipInfo = getClipInfoByCropDimensions(clipInfo, cropDimensions);
if (markSeedPosition && markSeedPosition.y === clipInfo.clipBottom)
clipInfo.clipBottom--;
return clipInfo;
}
export async function cropScreenshot (image, { path, markSeedPosition, clientAreaDimensions, cropDimensions }) {
if (!markSeedPosition && !cropDimensions)
return null;
const clip = calculateClipInfo(image, markSeedPosition, clientAreaDimensions, cropDimensions);
await validateClipInfo(clip, path);
return copyImagePart(image, clip);
}