fast_resize 1.0.2 → 1.0.3

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bindings/ruby/ext/fastresize/extconf.rb +79 -105
  4. data/bindings/ruby/lib/fastresize/platform.rb +102 -56
  5. data/bindings/ruby/lib/fastresize/version.rb +1 -1
  6. data/bindings/ruby/lib/fastresize.rb +321 -6
  7. data/bindings/ruby/prebuilt/linux-aarch64/bin/fast_resize +0 -0
  8. data/bindings/ruby/prebuilt/linux-aarch64.tar.gz +0 -0
  9. data/bindings/ruby/prebuilt/linux-x86_64/bin/fast_resize +0 -0
  10. data/bindings/ruby/prebuilt/linux-x86_64/lib/libfastresize.a +0 -0
  11. data/bindings/ruby/prebuilt/linux-x86_64.tar.gz +0 -0
  12. data/bindings/ruby/prebuilt/macos-arm64/bin/fast_resize +0 -0
  13. data/bindings/ruby/prebuilt/macos-arm64/lib/libfastresize.a +0 -0
  14. data/bindings/ruby/prebuilt/macos-arm64.tar.gz +0 -0
  15. data/bindings/ruby/prebuilt/macos-x86_64/bin/fast_resize +0 -0
  16. data/bindings/ruby/prebuilt/macos-x86_64/lib/libfastresize.a +0 -0
  17. data/bindings/ruby/prebuilt/macos-x86_64.tar.gz +0 -0
  18. metadata +4 -22
  19. data/CMakeLists.txt +0 -311
  20. data/bindings/ruby/ext/fastresize/fastresize_ext.cpp +0 -377
  21. data/include/fastresize.h +0 -189
  22. data/include/stb_image.h +0 -7988
  23. data/include/stb_image_resize2.h +0 -10651
  24. data/include/stb_image_write.h +0 -1724
  25. data/src/cli.cpp +0 -540
  26. data/src/decoder.cpp +0 -647
  27. data/src/encoder.cpp +0 -376
  28. data/src/fastresize.cpp +0 -445
  29. data/src/internal.h +0 -108
  30. data/src/pipeline.cpp +0 -284
  31. data/src/pipeline.h +0 -175
  32. data/src/resizer.cpp +0 -199
  33. data/src/simd_resize.cpp +0 -384
  34. data/src/simd_resize.h +0 -72
  35. data/src/simd_utils.h +0 -127
  36. data/src/thread_pool.cpp +0 -232
data/src/decoder.cpp DELETED
@@ -1,647 +0,0 @@
1
- /*
2
- * FastResize - The Fastest Image Resizing Library On The Planet
3
- * Copyright (C) 2025 Tran Huu Canh (0xTh3OKrypt) and FastResize Contributors
4
- *
5
- * Resize 1,000 images in 2 seconds. Up to 2.9x faster than libvips,
6
- * 3.1x faster than imageflow. Uses 3-4x less RAM than alternatives.
7
- *
8
- * Author: Tran Huu Canh (0xTh3OKrypt)
9
- * Email: tranhuucanh39@gmail.com
10
- * Homepage: https://github.com/tranhuucanh/fast_resize
11
- *
12
- * BSD 3-Clause License
13
- *
14
- * Redistribution and use in source and binary forms, with or without
15
- * modification, are permitted provided that the following conditions are met:
16
- *
17
- * 1. Redistributions of source code must retain the above copyright notice,
18
- * this list of conditions and the following disclaimer.
19
- *
20
- * 2. Redistributions in binary form must reproduce the above copyright notice,
21
- * this list of conditions and the following disclaimer in the documentation
22
- * and/or other materials provided with the distribution.
23
- *
24
- * 3. Neither the name of the copyright holder nor the names of its
25
- * contributors may be used to endorse or promote products derived from
26
- * this software without specific prior written permission.
27
- *
28
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
32
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
38
- * THE POSSIBILITY OF SUCH DAMAGE.
39
- */
40
-
41
- #include "internal.h"
42
- #include <cstdio>
43
- #include <cstring>
44
- #include <csetjmp>
45
-
46
- #include <jpeglib.h>
47
- #include <png.h>
48
- #include <webp/decode.h>
49
-
50
- #define STB_IMAGE_IMPLEMENTATION
51
- #include "stb_image.h"
52
-
53
- #ifndef _WIN32
54
- #include <sys/mman.h>
55
- #include <sys/stat.h>
56
- #include <fcntl.h>
57
- #include <unistd.h>
58
- #else
59
- #include <windows.h>
60
- #endif
61
-
62
- #include "simd_utils.h"
63
-
64
- namespace fastresize {
65
- namespace internal {
66
-
67
- // ============================================
68
- // Memory-Mapped File
69
- // ============================================
70
-
71
- struct MappedFile {
72
- void* data;
73
- size_t size;
74
- int fd;
75
-
76
- #ifdef _WIN32
77
- HANDLE hFile;
78
- HANDLE hMapping;
79
- #endif
80
-
81
- MappedFile() : data(nullptr), size(0), fd(-1) {
82
- #ifdef _WIN32
83
- hFile = INVALID_HANDLE_VALUE;
84
- hMapping = nullptr;
85
- #endif
86
- }
87
-
88
- ~MappedFile() {
89
- unmap();
90
- }
91
-
92
- bool map(const std::string& path) {
93
- #ifdef _WIN32
94
- // Windows implementation
95
- hFile = CreateFileA(path.c_str(), GENERIC_READ,
96
- FILE_SHARE_READ, NULL,
97
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
98
- if (hFile == INVALID_HANDLE_VALUE) return false;
99
-
100
- hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
101
- if (!hMapping) {
102
- CloseHandle(hFile);
103
- hFile = INVALID_HANDLE_VALUE;
104
- return false;
105
- }
106
-
107
- data = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
108
- LARGE_INTEGER fileSize;
109
- GetFileSizeEx(hFile, &fileSize);
110
- size = fileSize.QuadPart;
111
-
112
- if (!data) {
113
- CloseHandle(hMapping);
114
- CloseHandle(hFile);
115
- hMapping = nullptr;
116
- hFile = INVALID_HANDLE_VALUE;
117
- return false;
118
- }
119
- #else
120
- // Unix/macOS implementation
121
- fd = open(path.c_str(), O_RDONLY);
122
- if (fd < 0) return false;
123
-
124
- struct stat sb;
125
- if (fstat(fd, &sb) < 0) {
126
- close(fd);
127
- fd = -1;
128
- return false;
129
- }
130
-
131
- size = sb.st_size;
132
- if (size == 0) {
133
- close(fd);
134
- fd = -1;
135
- return false;
136
- }
137
-
138
- data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
139
- if (data == MAP_FAILED) {
140
- close(fd);
141
- fd = -1;
142
- data = nullptr;
143
- return false;
144
- }
145
- #endif
146
- return data != nullptr;
147
- }
148
-
149
- void unmap() {
150
- if (data) {
151
- #ifdef _WIN32
152
- UnmapViewOfFile(data);
153
- if (hMapping) CloseHandle(hMapping);
154
- if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
155
- hMapping = nullptr;
156
- hFile = INVALID_HANDLE_VALUE;
157
- #else
158
- munmap(data, size);
159
- if (fd >= 0) close(fd);
160
- fd = -1;
161
- #endif
162
- data = nullptr;
163
- size = 0;
164
- }
165
- }
166
- };
167
-
168
- // ============================================
169
- // Image Format Detection
170
- // ============================================
171
-
172
- ImageFormat detect_format(const std::string& path) {
173
- FILE* f = fopen(path.c_str(), "rb");
174
- if (!f) return FORMAT_UNKNOWN;
175
-
176
- unsigned char header[12];
177
- size_t n = fread(header, 1, 12, f);
178
- fclose(f);
179
-
180
- if (n < 4) return FORMAT_UNKNOWN;
181
-
182
- if (header[0] == 0xFF && header[1] == 0xD8 && header[2] == 0xFF)
183
- return FORMAT_JPEG;
184
-
185
- if (header[0] == 0x89 && header[1] == 0x50 &&
186
- header[2] == 0x4E && header[3] == 0x47)
187
- return FORMAT_PNG;
188
-
189
- if (n >= 12 &&
190
- header[0] == 'R' && header[1] == 'I' &&
191
- header[2] == 'F' && header[3] == 'F' &&
192
- header[8] == 'W' && header[9] == 'E' &&
193
- header[10] == 'B' && header[11] == 'P')
194
- return FORMAT_WEBP;
195
-
196
- if (header[0] == 'B' && header[1] == 'M')
197
- return FORMAT_BMP;
198
-
199
- return FORMAT_UNKNOWN;
200
- }
201
-
202
- std::string format_to_string(ImageFormat format) {
203
- switch (format) {
204
- case FORMAT_JPEG: return "jpg";
205
- case FORMAT_PNG: return "png";
206
- case FORMAT_WEBP: return "webp";
207
- case FORMAT_BMP: return "bmp";
208
- default: return "unknown";
209
- }
210
- }
211
-
212
- ImageFormat string_to_format(const std::string& str) {
213
- if (str == "jpg" || str == "jpeg") return FORMAT_JPEG;
214
- if (str == "png") return FORMAT_PNG;
215
- if (str == "webp") return FORMAT_WEBP;
216
- if (str == "bmp") return FORMAT_BMP;
217
- return FORMAT_UNKNOWN;
218
- }
219
-
220
- // ============================================
221
- // JPEG Decoding
222
- // ============================================
223
-
224
- struct jpeg_error_mgr_ext {
225
- struct jpeg_error_mgr pub;
226
- jmp_buf setjmp_buffer;
227
- };
228
-
229
- static void jpeg_error_exit(j_common_ptr cinfo) {
230
- jpeg_error_mgr_ext* myerr = (jpeg_error_mgr_ext*)cinfo->err;
231
- longjmp(myerr->setjmp_buffer, 1);
232
- }
233
-
234
- ImageData decode_jpeg(const std::string& path) {
235
- ImageData data;
236
- data.pixels = nullptr;
237
- data.width = 0;
238
- data.height = 0;
239
- data.channels = 0;
240
-
241
- MappedFile mapped;
242
- if (!mapped.map(path)) {
243
- FILE* infile = fopen(path.c_str(), "rb");
244
- if (!infile) return data;
245
-
246
- struct jpeg_decompress_struct cinfo;
247
- struct jpeg_error_mgr_ext jerr;
248
-
249
- cinfo.err = jpeg_std_error(&jerr.pub);
250
- jerr.pub.error_exit = jpeg_error_exit;
251
-
252
- if (setjmp(jerr.setjmp_buffer)) {
253
- jpeg_destroy_decompress(&cinfo);
254
- fclose(infile);
255
- return data;
256
- }
257
-
258
- jpeg_create_decompress(&cinfo);
259
- jpeg_stdio_src(&cinfo, infile);
260
- jpeg_read_header(&cinfo, TRUE);
261
-
262
- cinfo.dct_method = JDCT_IFAST;
263
- cinfo.do_fancy_upsampling = FALSE;
264
-
265
- jpeg_start_decompress(&cinfo);
266
-
267
- data.width = cinfo.output_width;
268
- data.height = cinfo.output_height;
269
- data.channels = cinfo.output_components;
270
-
271
- size_t row_stride = data.width * data.channels;
272
- data.pixels = new unsigned char[data.height * row_stride];
273
-
274
- JSAMPROW row_pointer[1];
275
- while (cinfo.output_scanline < cinfo.output_height) {
276
- row_pointer[0] = &data.pixels[cinfo.output_scanline * row_stride];
277
- jpeg_read_scanlines(&cinfo, row_pointer, 1);
278
- }
279
-
280
- jpeg_finish_decompress(&cinfo);
281
- jpeg_destroy_decompress(&cinfo);
282
- fclose(infile);
283
-
284
- return data;
285
- }
286
-
287
- struct jpeg_decompress_struct cinfo;
288
- struct jpeg_error_mgr_ext jerr;
289
-
290
- cinfo.err = jpeg_std_error(&jerr.pub);
291
- jerr.pub.error_exit = jpeg_error_exit;
292
-
293
- if (setjmp(jerr.setjmp_buffer)) {
294
- jpeg_destroy_decompress(&cinfo);
295
- return data;
296
- }
297
-
298
- jpeg_create_decompress(&cinfo);
299
- jpeg_mem_src(&cinfo, (unsigned char*)mapped.data, mapped.size);
300
- jpeg_read_header(&cinfo, TRUE);
301
-
302
- cinfo.dct_method = JDCT_IFAST;
303
- cinfo.do_fancy_upsampling = FALSE;
304
-
305
- jpeg_start_decompress(&cinfo);
306
-
307
- data.width = cinfo.output_width;
308
- data.height = cinfo.output_height;
309
- data.channels = cinfo.output_components;
310
-
311
- size_t row_stride = data.width * data.channels;
312
- data.pixels = new unsigned char[data.height * row_stride];
313
-
314
- JSAMPROW row_pointer[1];
315
- while (cinfo.output_scanline < cinfo.output_height) {
316
- row_pointer[0] = &data.pixels[cinfo.output_scanline * row_stride];
317
- jpeg_read_scanlines(&cinfo, row_pointer, 1);
318
- }
319
-
320
- jpeg_finish_decompress(&cinfo);
321
- jpeg_destroy_decompress(&cinfo);
322
-
323
- return data;
324
- }
325
-
326
- // ============================================
327
- // PNG Decoding
328
- // ============================================
329
-
330
- struct PngMemoryReader {
331
- const unsigned char* data;
332
- size_t size;
333
- size_t offset;
334
- };
335
-
336
- static void png_read_from_memory(png_structp png, png_bytep out, png_size_t count) {
337
- PngMemoryReader* reader = (PngMemoryReader*)png_get_io_ptr(png);
338
- if (reader->offset + count > reader->size) {
339
- png_error(png, "Read past end of data");
340
- return;
341
- }
342
- memcpy(out, reader->data + reader->offset, count);
343
- reader->offset += count;
344
- }
345
-
346
- ImageData decode_png(const std::string& path) {
347
- ImageData data;
348
- data.pixels = nullptr;
349
- data.width = 0;
350
- data.height = 0;
351
- data.channels = 0;
352
-
353
- MappedFile mapped;
354
- PngMemoryReader mem_reader = {nullptr, 0, 0};
355
- FILE* fp = nullptr;
356
-
357
- bool use_mmap = mapped.map(path);
358
- if (use_mmap) {
359
- mem_reader.data = (const unsigned char*)mapped.data;
360
- mem_reader.size = mapped.size;
361
- mem_reader.offset = 0;
362
- } else {
363
- fp = fopen(path.c_str(), "rb");
364
- if (!fp) return data;
365
- }
366
-
367
- png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
368
- if (!png) {
369
- if (fp) fclose(fp);
370
- return data;
371
- }
372
-
373
- png_infop info = png_create_info_struct(png);
374
- if (!info) {
375
- png_destroy_read_struct(&png, nullptr, nullptr);
376
- if (fp) fclose(fp);
377
- return data;
378
- }
379
-
380
- if (setjmp(png_jmpbuf(png))) {
381
- png_destroy_read_struct(&png, &info, nullptr);
382
- if (fp) fclose(fp);
383
- if (data.pixels) delete[] data.pixels;
384
- data.pixels = nullptr;
385
- return data;
386
- }
387
-
388
- if (use_mmap) {
389
- png_set_read_fn(png, &mem_reader, png_read_from_memory);
390
- } else {
391
- png_init_io(png, fp);
392
- }
393
-
394
- png_read_info(png, info);
395
-
396
- data.width = png_get_image_width(png, info);
397
- data.height = png_get_image_height(png, info);
398
- png_byte color_type = png_get_color_type(png, info);
399
- png_byte bit_depth = png_get_bit_depth(png, info);
400
-
401
- if (bit_depth == 16)
402
- png_set_strip_16(png);
403
-
404
- if (color_type == PNG_COLOR_TYPE_PALETTE)
405
- png_set_palette_to_rgb(png);
406
-
407
- if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
408
- png_set_expand_gray_1_2_4_to_8(png);
409
-
410
- if (png_get_valid(png, info, PNG_INFO_tRNS))
411
- png_set_tRNS_to_alpha(png);
412
-
413
- png_read_update_info(png, info);
414
-
415
- switch (png_get_color_type(png, info)) {
416
- case PNG_COLOR_TYPE_GRAY:
417
- data.channels = 1;
418
- break;
419
- case PNG_COLOR_TYPE_GRAY_ALPHA:
420
- data.channels = 2;
421
- break;
422
- case PNG_COLOR_TYPE_RGB:
423
- data.channels = 3;
424
- break;
425
- case PNG_COLOR_TYPE_RGB_ALPHA:
426
- data.channels = 4;
427
- break;
428
- default:
429
- data.channels = 3;
430
- }
431
-
432
- size_t row_bytes = png_get_rowbytes(png, info);
433
- data.pixels = new unsigned char[data.height * row_bytes];
434
-
435
- png_bytep* row_pointers = new png_bytep[data.height];
436
- for (int y = 0; y < data.height; y++) {
437
- row_pointers[y] = data.pixels + y * row_bytes;
438
- }
439
-
440
- png_read_image(png, row_pointers);
441
- png_read_end(png, nullptr);
442
-
443
- delete[] row_pointers;
444
- png_destroy_read_struct(&png, &info, nullptr);
445
- if (fp) fclose(fp);
446
-
447
- return data;
448
- }
449
-
450
- // ============================================
451
- // WEBP Decoding
452
- // ============================================
453
-
454
- ImageData decode_webp(const std::string& path) {
455
- ImageData data;
456
- data.pixels = nullptr;
457
- data.width = 0;
458
- data.height = 0;
459
- data.channels = 0;
460
-
461
- MappedFile mapped;
462
- if (!mapped.map(path)) {
463
- FILE* fp = fopen(path.c_str(), "rb");
464
- if (!fp) return data;
465
-
466
- fseek(fp, 0, SEEK_END);
467
- long file_size = ftell(fp);
468
- fseek(fp, 0, SEEK_SET);
469
-
470
- if (file_size <= 0) {
471
- fclose(fp);
472
- return data;
473
- }
474
-
475
- unsigned char* file_data = new unsigned char[file_size];
476
- size_t read_size = fread(file_data, 1, file_size, fp);
477
- fclose(fp);
478
-
479
- if (read_size != (size_t)file_size) {
480
- delete[] file_data;
481
- return data;
482
- }
483
-
484
- WebPBitstreamFeatures features;
485
- if (WebPGetFeatures(file_data, file_size, &features) != VP8_STATUS_OK) {
486
- delete[] file_data;
487
- return data;
488
- }
489
-
490
- data.width = features.width;
491
- data.height = features.height;
492
- data.channels = features.has_alpha ? 4 : 3;
493
-
494
- unsigned char* webp_pixels = nullptr;
495
- if (data.channels == 4) {
496
- webp_pixels = WebPDecodeRGBA(file_data, file_size, &data.width, &data.height);
497
- } else {
498
- webp_pixels = WebPDecodeRGB(file_data, file_size, &data.width, &data.height);
499
- }
500
-
501
- delete[] file_data;
502
-
503
- if (!webp_pixels) {
504
- data.width = 0;
505
- data.height = 0;
506
- data.channels = 0;
507
- return data;
508
- }
509
-
510
- size_t pixel_count = data.width * data.height * data.channels;
511
- data.pixels = new unsigned char[pixel_count];
512
- fast_copy_aligned(data.pixels, webp_pixels, pixel_count);
513
- WebPFree(webp_pixels);
514
-
515
- return data;
516
- }
517
-
518
- WebPBitstreamFeatures features;
519
- if (WebPGetFeatures((unsigned char*)mapped.data, mapped.size, &features) != VP8_STATUS_OK) {
520
- return data;
521
- }
522
-
523
- data.width = features.width;
524
- data.height = features.height;
525
- data.channels = features.has_alpha ? 4 : 3;
526
-
527
- unsigned char* webp_pixels = nullptr;
528
- if (data.channels == 4) {
529
- webp_pixels = WebPDecodeRGBA((unsigned char*)mapped.data, mapped.size,
530
- &data.width, &data.height);
531
- } else {
532
- webp_pixels = WebPDecodeRGB((unsigned char*)mapped.data, mapped.size,
533
- &data.width, &data.height);
534
- }
535
-
536
- if (!webp_pixels) {
537
- data.width = 0;
538
- data.height = 0;
539
- data.channels = 0;
540
- return data;
541
- }
542
-
543
- size_t pixel_count = data.width * data.height * data.channels;
544
- data.pixels = new unsigned char[pixel_count];
545
- fast_copy_aligned(data.pixels, webp_pixels, pixel_count);
546
- WebPFree(webp_pixels);
547
-
548
- return data;
549
- }
550
-
551
- // ============================================
552
- // Image Decoding
553
- // ============================================
554
-
555
- ImageData decode_image(const std::string& path, ImageFormat format) {
556
- ImageData data;
557
- data.pixels = nullptr;
558
- data.width = 0;
559
- data.height = 0;
560
- data.channels = 0;
561
-
562
- switch (format) {
563
- case FORMAT_JPEG:
564
- return decode_jpeg(path);
565
- case FORMAT_PNG:
566
- return decode_png(path);
567
- case FORMAT_WEBP:
568
- return decode_webp(path);
569
- case FORMAT_BMP:
570
- data.pixels = stbi_load(path.c_str(),
571
- &data.width,
572
- &data.height,
573
- &data.channels,
574
- 0);
575
- return data;
576
- default:
577
- data.pixels = stbi_load(path.c_str(),
578
- &data.width,
579
- &data.height,
580
- &data.channels,
581
- 0);
582
- return data;
583
- }
584
- }
585
-
586
- void free_image_data(ImageData& data) {
587
- if (data.pixels) {
588
- delete[] data.pixels;
589
- data.pixels = nullptr;
590
- }
591
- }
592
-
593
- // ============================================
594
- // Image Info
595
- // ============================================
596
-
597
- bool get_image_dimensions(const std::string& path, int& width, int& height, int& channels) {
598
- ImageFormat format = detect_format(path);
599
-
600
- if (format == FORMAT_WEBP) {
601
- FILE* fp = fopen(path.c_str(), "rb");
602
- if (!fp) return false;
603
-
604
- fseek(fp, 0, SEEK_END);
605
- long file_size = ftell(fp);
606
- fseek(fp, 0, SEEK_SET);
607
-
608
- if (file_size <= 0) {
609
- fclose(fp);
610
- return false;
611
- }
612
-
613
- unsigned char* file_data = new unsigned char[file_size];
614
- size_t read_size = fread(file_data, 1, file_size, fp);
615
- fclose(fp);
616
-
617
- if (read_size != (size_t)file_size) {
618
- delete[] file_data;
619
- return false;
620
- }
621
-
622
- WebPBitstreamFeatures features;
623
- if (WebPGetFeatures(file_data, file_size, &features) == VP8_STATUS_OK) {
624
- width = features.width;
625
- height = features.height;
626
- channels = features.has_alpha ? 4 : 3;
627
- delete[] file_data;
628
- return true;
629
- }
630
-
631
- delete[] file_data;
632
- return false;
633
- } else {
634
- int w, h, c;
635
- int result = stbi_info(path.c_str(), &w, &h, &c);
636
- if (result) {
637
- width = w;
638
- height = h;
639
- channels = c;
640
- return true;
641
- }
642
- return false;
643
- }
644
- }
645
-
646
- }
647
- }