@qy_better_lib/hooks 0.2.6 → 0.2.8

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.
@@ -1,192 +0,0 @@
1
- import { download_file, to_base64, compress_image } from "@qy_better_lib/core";
2
- import { EImageType } from "./type.js";
3
- function use_image() {
4
- function check_image_type(type) {
5
- return Object.values(EImageType).includes(type);
6
- }
7
- async function canvas_to_data_url(canvas, quality = 0.92, type = EImageType.JPEG) {
8
- if (!check_image_type(type)) {
9
- type = EImageType.JPEG;
10
- }
11
- return canvas.toDataURL(type, quality);
12
- }
13
- async function canvas_to_file(canvas, file_name = "image", quality = 0.92, type = EImageType.JPEG) {
14
- const data_url = await canvas_to_data_url(canvas, quality, type);
15
- return data_url_to_file(data_url, type, file_name);
16
- }
17
- async function data_url_to_file(data_url, type = EImageType.JPEG, file_name = "image") {
18
- if (!check_image_type(type)) {
19
- type = EImageType.JPEG;
20
- }
21
- const arr = data_url.split(",");
22
- const mime = arr[0].match(/:(.*?);/)?.[1] || type;
23
- const bstr = atob(arr[1]);
24
- let n = bstr.length;
25
- const u8arr = new Uint8Array(n);
26
- while (n--) {
27
- u8arr[n] = bstr.charCodeAt(n);
28
- }
29
- const extension = mime.split("/")[1];
30
- const full_name = `${file_name}.${extension}`;
31
- return new File([u8arr], full_name, { type: mime });
32
- }
33
- async function data_url_to_image(data_url) {
34
- return new Promise((resolve, reject) => {
35
- const image = new Image();
36
- image.onload = () => resolve(image);
37
- image.onerror = reject;
38
- image.src = data_url;
39
- });
40
- }
41
- function download_file$1(blob, file_name = "download") {
42
- const url = URL.createObjectURL(blob);
43
- download_file({ path: url, name: file_name });
44
- URL.revokeObjectURL(url);
45
- }
46
- async function file_to_data_url(file) {
47
- const result = await to_base64(file);
48
- if (!result) {
49
- throw new Error("转换文件为DataURL失败");
50
- }
51
- return result;
52
- }
53
- async function image_to_canvas(image, config = {}) {
54
- const canvas = document.createElement("canvas");
55
- const context = canvas.getContext("2d");
56
- if (!context) {
57
- throw new Error("创建Canvas上下文失败");
58
- }
59
- const width = config.width || image.width;
60
- const height = config.height || image.height;
61
- const scale = config.scale || 1;
62
- canvas.width = width * scale;
63
- canvas.height = height * scale;
64
- context.scale(scale, scale);
65
- context.drawImage(image, 0, 0, width, height);
66
- return canvas;
67
- }
68
- async function url_to_blob(url) {
69
- const response = await fetch(url);
70
- if (!response.ok) {
71
- throw new Error(`获取图片失败: ${response.statusText}`);
72
- }
73
- return response.blob();
74
- }
75
- async function url_to_image(url) {
76
- return new Promise((resolve, reject) => {
77
- const image = new Image();
78
- image.onload = () => resolve(image);
79
- image.onerror = reject;
80
- image.src = url;
81
- });
82
- }
83
- async function compress(file, config = {}) {
84
- if (!(file instanceof Blob)) {
85
- throw new Error("compress(): 第一个参数必须是Blob对象或File对象");
86
- }
87
- const quality = Math.max(0, Math.min(1, isNaN(Number(config.quality)) ? 0.92 : Number(config.quality)));
88
- config.quality = quality;
89
- const data_url = await file_to_data_url(file);
90
- const original_mime = data_url.split(",")[0].match(/:(.*?);/)?.[1];
91
- let mime = EImageType.JPEG;
92
- if (check_image_type(config.type)) {
93
- mime = config.type;
94
- }
95
- const image = await data_url_to_image(data_url);
96
- const canvas = await image_to_canvas(image, config);
97
- const compress_data_url = await canvas_to_data_url(canvas, config.quality, mime);
98
- const compress_file = await data_url_to_file(compress_data_url, original_mime || mime);
99
- if (compress_file.size > file.size) {
100
- return file;
101
- }
102
- return compress_file;
103
- }
104
- async function compress_accurately(file, config = {}) {
105
- if (!(file instanceof Blob)) {
106
- throw new Error("compressAccurately(): 第一个参数必须是Blob对象或File对象");
107
- }
108
- const size = Math.max(0, isNaN(Number(config.size)) ? 0 : Number(config.size));
109
- config.size = size;
110
- const accuracy = Math.max(0.8, Math.min(0.99, isNaN(Number(config.accuracy)) ? 0.95 : Number(config.accuracy)));
111
- config.accuracy = accuracy;
112
- if (isNaN(config.size)) {
113
- return file;
114
- }
115
- if (config.size * 1024 > file.size) {
116
- return file;
117
- }
118
- if (!config.accuracy || config.accuracy < 0.8 || config.accuracy > 0.99) {
119
- config.accuracy = 0.95;
120
- }
121
- const result_size = {
122
- max: config.size * (2 - config.accuracy) * 1024,
123
- accurate: config.size * 1024,
124
- min: config.size * config.accuracy * 1024
125
- };
126
- const data_url = await file_to_data_url(file);
127
- const original_mime = data_url.split(",")[0].match(/:(.*?);/)?.[1];
128
- let mime = EImageType.JPEG;
129
- if (check_image_type(config.type)) {
130
- mime = config.type;
131
- }
132
- const image = await data_url_to_image(data_url);
133
- const canvas = await image_to_canvas(image, config);
134
- const proportion = 0.75;
135
- let image_quality = 1;
136
- let compress_data_url = "";
137
- const temp_data_urls = [];
138
- for (let x = 1; x <= 7; x++) {
139
- compress_data_url = await canvas_to_data_url(canvas, image_quality, mime);
140
- const calculation_size = compress_data_url.length * proportion;
141
- if (x === 7) {
142
- if (result_size.max < calculation_size || result_size.min > calculation_size) {
143
- compress_data_url = [compress_data_url, ...temp_data_urls].filter(Boolean).sort(
144
- (a, b) => Math.abs(a.length * proportion - result_size.accurate) - Math.abs(b.length * proportion - result_size.accurate)
145
- )[0];
146
- }
147
- break;
148
- }
149
- if (result_size.max < calculation_size) {
150
- temp_data_urls[1] = compress_data_url;
151
- image_quality -= 0.5 ** (x + 1);
152
- } else if (result_size.min > calculation_size) {
153
- temp_data_urls[0] = compress_data_url;
154
- image_quality += 0.5 ** (x + 1);
155
- } else {
156
- break;
157
- }
158
- }
159
- const compress_file = await data_url_to_file(
160
- compress_data_url,
161
- original_mime || mime
162
- );
163
- if (compress_file.size > file.size) {
164
- return file;
165
- }
166
- return compress_file;
167
- }
168
- async function compress_image$1(file, max_width = 800, max_height = 800, quality = 0.8) {
169
- return compress_image(file, max_width, max_height, quality);
170
- }
171
- return {
172
- // 压缩功能
173
- compress,
174
- compress_accurately,
175
- compress_image: compress_image$1,
176
- // 转换功能
177
- canvas_to_data_url,
178
- canvas_to_file,
179
- data_url_to_file,
180
- data_url_to_image,
181
- file_to_data_url,
182
- image_to_canvas,
183
- url_to_blob,
184
- url_to_image,
185
- // 工具功能
186
- download_file: download_file$1
187
- };
188
- }
189
- export {
190
- EImageType,
191
- use_image
192
- };
@@ -1,9 +0,0 @@
1
- var EImageType = /* @__PURE__ */ ((EImageType2) => {
2
- EImageType2["PNG"] = "image/png";
3
- EImageType2["JPEG"] = "image/jpeg";
4
- EImageType2["GIF"] = "image/gif";
5
- return EImageType2;
6
- })(EImageType || {});
7
- export {
8
- EImageType
9
- };
@@ -1,301 +0,0 @@
1
- function use_print() {
2
- let preview_container = null;
3
- let print_in_progress = false;
4
- function get_style(custom_style, options) {
5
- const page_size = options?.page_size || "A4";
6
- const page_orientation = options?.page_orientation || "portrait";
7
- const margin = options?.margin || "1cm";
8
- const print_background = options?.print_background ? "true" : "false";
9
- const default_style = `#print-container {
10
- display: none;
11
- }
12
- #preview-container {
13
- position: fixed;
14
- top: 0;
15
- left: 0;
16
- width: 100%;
17
- height: 100%;
18
- background: rgba(0, 0, 0, 0.8);
19
- display: flex;
20
- justify-content: center;
21
- align-items: center;
22
- z-index: 9999;
23
- overflow: auto;
24
- }
25
- #preview-content {
26
- background: white;
27
- width: 80%;
28
- max-width: 800px;
29
- padding: 20px;
30
- box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
31
- position: relative;
32
- }
33
- #preview-close {
34
- position: absolute;
35
- top: 10px;
36
- right: 10px;
37
- background: #333;
38
- color: white;
39
- border: none;
40
- border-radius: 50%;
41
- width: 30px;
42
- height: 30px;
43
- cursor: pointer;
44
- font-size: 16px;
45
- display: flex;
46
- justify-content: center;
47
- align-items: center;
48
- }
49
- #preview-print {
50
- margin-top: 20px;
51
- padding: 10px 20px;
52
- background: #007bff;
53
- color: white;
54
- border: none;
55
- border-radius: 4px;
56
- cursor: pointer;
57
- font-size: 16px;
58
- }
59
- @media print {
60
- body > :not(#print-container) {
61
- display: none;
62
- }
63
- html,
64
- body {
65
- display: block !important;
66
- margin: 0;
67
- padding: 0;
68
- width: 100%;
69
- height: 100%;
70
- -webkit-print-color-adjust: ${print_background};
71
- print-color-adjust: ${print_background};
72
- }
73
- #print-container {
74
- display: block;
75
- padding: 20px;
76
- width: 100%;
77
- height: 100%;
78
- box-sizing: border-box;
79
- }
80
- }
81
- @page {
82
- size: ${page_size} ${page_orientation};
83
- margin: ${margin};
84
- }`;
85
- const style = document.createElement("style");
86
- style.innerHTML = custom_style || default_style;
87
- return style;
88
- }
89
- function clean_print() {
90
- const existing_container = document.getElementById("print-container");
91
- if (existing_container) {
92
- try {
93
- document.body.removeChild(existing_container);
94
- } catch (error) {
95
- console.error("清理打印容器失败:", error);
96
- }
97
- }
98
- }
99
- function clean_preview() {
100
- const existing_preview = document.getElementById("preview-container");
101
- if (existing_preview) {
102
- try {
103
- document.body.removeChild(existing_preview);
104
- preview_container = null;
105
- } catch (error) {
106
- console.error("清理预览容器失败:", error);
107
- }
108
- }
109
- }
110
- function get_container(html_content) {
111
- clean_print();
112
- const container = document.createElement("div");
113
- container.setAttribute("id", "print-container");
114
- container.innerHTML = html_content;
115
- return container;
116
- }
117
- function get_load_promise(container) {
118
- if (!container || typeof container.querySelectorAll !== "function") {
119
- return Promise.resolve();
120
- }
121
- const img_elements = container.querySelectorAll("img");
122
- const imgs = Array.from(img_elements);
123
- if (imgs.length === 0) {
124
- return Promise.resolve();
125
- }
126
- let finished_count = 0;
127
- return new Promise((resolve, reject) => {
128
- function check() {
129
- finished_count++;
130
- if (finished_count === imgs.length) {
131
- resolve();
132
- }
133
- }
134
- imgs.forEach((img) => {
135
- if (img.complete) {
136
- check();
137
- } else {
138
- img.addEventListener("load", check);
139
- img.addEventListener("error", check);
140
- }
141
- });
142
- setTimeout(() => {
143
- reject(new Error("图片加载超时"));
144
- }, 1e4);
145
- });
146
- }
147
- async function print(html_content, options) {
148
- if (print_in_progress) {
149
- console.warn("打印已在进行中");
150
- return;
151
- }
152
- try {
153
- print_in_progress = true;
154
- const style = get_style(options?.custom_style, options);
155
- const container = get_container(html_content);
156
- document.body.appendChild(style);
157
- document.body.appendChild(container);
158
- await get_load_promise(container);
159
- window.print();
160
- setTimeout(() => {
161
- try {
162
- if (style.parentNode) {
163
- style.parentNode.removeChild(style);
164
- }
165
- if (container.parentNode) {
166
- container.parentNode.removeChild(container);
167
- }
168
- print_in_progress = false;
169
- options?.on_complete?.();
170
- } catch (error) {
171
- console.error("清理打印元素失败:", error);
172
- options?.on_error?.(error);
173
- }
174
- }, 100);
175
- } catch (error) {
176
- console.error("打印失败:", error);
177
- print_in_progress = false;
178
- options?.on_error?.(error);
179
- }
180
- }
181
- async function preview(html_content, options) {
182
- try {
183
- clean_preview();
184
- const style = get_style(options?.custom_style, options);
185
- const content = document.createElement("div");
186
- content.innerHTML = html_content;
187
- await get_load_promise(content);
188
- const preview_wrapper = document.createElement("div");
189
- preview_wrapper.setAttribute("id", "preview-container");
190
- const preview_content = document.createElement("div");
191
- preview_content.setAttribute("id", "preview-content");
192
- preview_content.appendChild(content);
193
- const close_button = document.createElement("button");
194
- close_button.setAttribute("id", "preview-close");
195
- close_button.textContent = "×";
196
- close_button.addEventListener("click", () => {
197
- clean_preview();
198
- options?.on_cancel?.();
199
- });
200
- const print_button = document.createElement("button");
201
- print_button.setAttribute("id", "preview-print");
202
- print_button.textContent = "打印";
203
- print_button.addEventListener("click", () => {
204
- clean_preview();
205
- print(html_content, options);
206
- });
207
- preview_content.appendChild(close_button);
208
- preview_content.appendChild(print_button);
209
- preview_wrapper.appendChild(preview_content);
210
- document.body.appendChild(style);
211
- document.body.appendChild(preview_wrapper);
212
- preview_container = preview_wrapper;
213
- } catch (error) {
214
- console.error("预览失败:", error);
215
- options?.on_error?.(error);
216
- }
217
- }
218
- async function print_html(dom_selector, options) {
219
- try {
220
- const target_element = document.querySelector(dom_selector);
221
- if (target_element) {
222
- if (options?.preview) {
223
- await preview(target_element.innerHTML, options);
224
- } else {
225
- await print(target_element.innerHTML, options);
226
- }
227
- } else {
228
- throw new Error(`未找到DOM节点: ${dom_selector}`);
229
- }
230
- } catch (error) {
231
- console.error("打印DOM元素失败:", error);
232
- options?.on_error?.(error);
233
- }
234
- }
235
- async function print_html_element(element_array, options) {
236
- try {
237
- if (!element_array || element_array.length === 0) {
238
- throw new Error("元素数组为空");
239
- }
240
- let html_content = "";
241
- for (const element of element_array) {
242
- html_content += element.outerHTML;
243
- }
244
- if (!html_content) {
245
- throw new Error("元素内容为空");
246
- }
247
- if (options?.preview) {
248
- await preview(html_content, options);
249
- } else {
250
- await print(html_content, options);
251
- }
252
- } catch (error) {
253
- console.error("打印元素数组失败:", error);
254
- options?.on_error?.(error);
255
- }
256
- }
257
- function preview_html(dom_selector, options) {
258
- try {
259
- const target_element = document.querySelector(dom_selector);
260
- if (target_element) {
261
- preview(target_element.innerHTML, options);
262
- } else {
263
- throw new Error(`未找到DOM节点: ${dom_selector}`);
264
- }
265
- } catch (error) {
266
- console.error("预览DOM元素失败:", error);
267
- options?.on_error?.(error);
268
- }
269
- }
270
- function preview_html_element(element_array, options) {
271
- try {
272
- if (!element_array || element_array.length === 0) {
273
- throw new Error("元素数组为空");
274
- }
275
- let html_content = "";
276
- for (const element of element_array) {
277
- html_content += element.outerHTML;
278
- }
279
- if (!html_content) {
280
- throw new Error("元素内容为空");
281
- }
282
- preview(html_content, options);
283
- } catch (error) {
284
- console.error("预览元素数组失败:", error);
285
- options?.on_error?.(error);
286
- }
287
- }
288
- function close_preview() {
289
- clean_preview();
290
- }
291
- return {
292
- print_html,
293
- print_html_element,
294
- preview_html,
295
- preview_html_element,
296
- close_preview
297
- };
298
- }
299
- export {
300
- use_print
301
- };
@@ -1,131 +0,0 @@
1
- import { guid, on, off, get_window_size, get_element } from "@qy_better_lib/core";
2
- function use_water_mark() {
3
- const id = guid();
4
- let current_options = null;
5
- let resize_handler = null;
6
- function get_wrapper(wrapper) {
7
- return wrapper ? get_element(wrapper) || document.body : document.body;
8
- }
9
- function create_watermark_canvas(options) {
10
- const { text1, text2, font_size = 16, font_family = "Avenir,Helvetica,Arial,sans-serif", rotate = -15, text_color = "#999", opacity = 0.1, size = { width: 250, height: 150 } } = options;
11
- try {
12
- const canvas = document.createElement("canvas");
13
- canvas.width = size.width;
14
- canvas.height = size.height;
15
- const ctx = canvas.getContext("2d");
16
- if (ctx) {
17
- ctx.font = `${font_size}px ${font_family}`;
18
- ctx.fillStyle = text_color.replace(/\,\s(1|(0\.\d+)\))/, `, ${opacity}`);
19
- ctx.textAlign = "left";
20
- ctx.textBaseline = "middle";
21
- ctx.rotate(rotate * Math.PI / 180);
22
- ctx.fillText(text1, 0, canvas.height / 2);
23
- if (text2) {
24
- const text1_width = ctx.measureText(text1).width;
25
- ctx.fillText(text2, text1_width + 16, canvas.height / 2);
26
- }
27
- }
28
- return canvas;
29
- } catch (error) {
30
- console.error("创建水印画布失败:", error);
31
- const canvas = document.createElement("canvas");
32
- canvas.width = 0;
33
- canvas.height = 0;
34
- return canvas;
35
- }
36
- }
37
- function create_watermark_element(options) {
38
- const {
39
- wrapper,
40
- z_index = 1e5,
41
- position = "fixed",
42
- spacing = 0,
43
- size = { width: 250, height: 150 }
44
- } = options;
45
- const wrapper_element = get_wrapper(wrapper);
46
- const existing_element = document.getElementById(id);
47
- if (existing_element) {
48
- try {
49
- wrapper_element.removeChild(existing_element);
50
- } catch (error) {
51
- console.error("移除旧水印失败:", error);
52
- }
53
- }
54
- const canvas = create_watermark_canvas(options);
55
- const div = document.createElement("div");
56
- div.id = id;
57
- div.style.pointerEvents = "none";
58
- div.style.top = "0px";
59
- div.style.left = "0px";
60
- div.style.position = position;
61
- div.style.zIndex = z_index.toString();
62
- const window_size = get_window_size();
63
- div.style.width = window_size.width + "px";
64
- div.style.height = window_size.height + "px";
65
- div.style.background = `url(${canvas.toDataURL("image/png")}) left top repeat`;
66
- if (spacing > 0) {
67
- div.style.backgroundSize = `${size.width + spacing}px ${size.height + spacing}px`;
68
- }
69
- try {
70
- wrapper_element.appendChild(div);
71
- } catch (error) {
72
- console.error("添加水印失败:", error);
73
- }
74
- }
75
- function handle_resize() {
76
- if (current_options) {
77
- create_watermark_element(current_options);
78
- }
79
- }
80
- function create_water_mark(options) {
81
- current_options = options;
82
- create_watermark_element(options);
83
- if (options.responsive) {
84
- if (!resize_handler) {
85
- resize_handler = handle_resize;
86
- on(window, "resize", resize_handler);
87
- }
88
- } else if (resize_handler) {
89
- off(window, "resize", resize_handler);
90
- resize_handler = null;
91
- }
92
- }
93
- function remove_water_mark() {
94
- const existing_element = document.getElementById(id);
95
- if (existing_element) {
96
- try {
97
- const parent = existing_element.parentElement;
98
- if (parent) {
99
- parent.removeChild(existing_element);
100
- }
101
- } catch (error) {
102
- console.error("移除水印失败:", error);
103
- }
104
- }
105
- if (resize_handler) {
106
- off(window, "resize", resize_handler);
107
- resize_handler = null;
108
- }
109
- current_options = null;
110
- }
111
- function update_water_mark(options) {
112
- if (current_options) {
113
- const new_options = { ...current_options, ...options };
114
- create_water_mark(new_options);
115
- } else {
116
- console.warn("水印未初始化,请先调用 create_water_mark");
117
- }
118
- }
119
- function has_water_mark() {
120
- return document.getElementById(id) !== null;
121
- }
122
- return {
123
- create_water_mark,
124
- remove_water_mark,
125
- update_water_mark,
126
- has_water_mark
127
- };
128
- }
129
- export {
130
- use_water_mark
131
- };