diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json deleted file mode 100644 index 8c7a55b..0000000 --- a/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "configurations": [ - { - "name": "Win32", - "includePath": [ - "${workspaceFolder}/node_modules/node-addon-api/**", - "${workspaceFolder}/color-quant", - "${workspaceFolder}/color-quant/src", - "${workspaceFolder}/color-quant/heap/src" - ], - "defines": [ - "_DEBUG", - "UNICODE", - "_UNICODE", - "HOST_BINARY \"node.exe\"" - ], - "windowsSdkVersion": "10.0.17763.0", - "compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.16.27023/bin/Hostx64/x64/cl.exe", - "cStandard": "c11", - "cppStandard": "c++17", - "intelliSenseMode": "msvc-x64" - } - ], - "version": 4 -} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index d3513cc..1151fa8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 2.8) - +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) project(cquant) diff --git a/README.md b/README.md index 042b362..e580cdc 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,8 @@ [![Build Status](https://travis-ci.org/xVanTuring/cquant.svg?branch=master)](https://travis-ci.org/xVanTuring/cquant) ## View Latest Doc on [Github](https://github.com/xVanTuring/cquant) ## Preview - - - +![Screenshot from 2019-02-09 15-16-53.png](https://i.loli.net/2019/02/09/5c5e7e7b2d278.png) +![Screenshot from 2019-02-09 15-16-32.png](https://i.loli.net/2019/02/09/5c5e7e7b42cd2.png) ## Usage > Current Supported Prebuild binary version: Node 6 | 8 | 10 | 11 \ diff --git a/TODO.md b/TODO.md index 2f3e2d8..f90b208 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,5 @@ -0. add test -1. add para for subsampling +0. ~~add test~~ +1. ~~add para for subsampling~~ 2. use typescript wrapper -3. add travis-ci +3. ~~add travis-ci~~ 4. remove rgba or not \ No newline at end of file diff --git a/compile_commands.json b/compile_commands.json new file mode 120000 index 0000000..affbd32 --- /dev/null +++ b/compile_commands.json @@ -0,0 +1 @@ +./build/compile_commands.json \ No newline at end of file diff --git a/cquant.js b/cquant.js index e77c205..2bc3e65 100644 --- a/cquant.js +++ b/cquant.js @@ -1,14 +1,14 @@ const addon = require('bindings')('cquant') -function paletteAsync (buffer, depth, maxColor = 5, callback = null) { +function paletteAsync(buffer, depth, maxColor = 5, maxSub = 0, callback = null) { if (callback == null) { if (depth !== 3 && depth !== 4) { - return Promise.reject(new Error('Wrong Depth')); + return Promise.reject(new Error('Wrong depth!')); } if (maxColor <= 1 || maxColor > 256) { - return Promise.reject(new Error('maxColor too small or too large')); + return Promise.reject(new Error('maxColor too small or too large!')); } return new Promise((res, rej) => { - addon.PaletteAsync(buffer, maxColor, depth, (err, val) => { + addon.PaletteAsync(buffer, maxColor, depth, maxSub, (err, val) => { if (err) { rej(err) } else { @@ -18,14 +18,14 @@ function paletteAsync (buffer, depth, maxColor = 5, callback = null) { }) } else { if (depth !== 3 && depth !== 4) { - callback(new Error('Wrong Depth')); + callback(new Error('Wrong depth!')); return; } if (maxColor <= 1 || maxColor > 256) { - callback(new Error('maxColor too small or too large')) + callback(new Error('maxColor too small or too large!')) return } - addon.PaletteAsync(buffer, maxColor, depth, callback) + addon.PaletteAsync(buffer, maxColor, depth, maxSub, callback) } } module.exports = { diff --git a/img/0.jpg b/img/large.1.jpg similarity index 100% rename from img/0.jpg rename to img/large.1.jpg diff --git a/img/large.1.jpg.scaled.html b/img/large.1.jpg.scaled.html new file mode 100644 index 0000000..59b7ef8 --- /dev/null +++ b/img/large.1.jpg.scaled.html @@ -0,0 +1,23 @@ + + +
+ +
+ +
+ +
+ +
+ +
\ No newline at end of file diff --git a/img/2.png b/img/large.1.png similarity index 100% rename from img/2.png rename to img/large.1.png diff --git a/img/large.1.png.full.html b/img/large.1.png.full.html new file mode 100644 index 0000000..7a51a3a --- /dev/null +++ b/img/large.1.png.full.html @@ -0,0 +1,23 @@ + + +
+ +
+ +
+ +
+ +
+ +
\ No newline at end of file diff --git a/img/large.1.png.scaled.html b/img/large.1.png.scaled.html new file mode 100644 index 0000000..7a51a3a --- /dev/null +++ b/img/large.1.png.scaled.html @@ -0,0 +1,23 @@ + + +
+ +
+ +
+ +
+ +
+ +
\ No newline at end of file diff --git a/img/1.jpg b/img/large.2.jpg similarity index 100% rename from img/1.jpg rename to img/large.2.jpg diff --git a/img/1.jpg.html b/img/large.2.jpg.full.html similarity index 71% rename from img/1.jpg.html rename to img/large.2.jpg.full.html index e192f49..34896f3 100644 --- a/img/1.jpg.html +++ b/img/large.2.jpg.full.html @@ -10,7 +10,7 @@ display: block; } -
+
@@ -18,6 +18,6 @@
-
+
\ No newline at end of file diff --git a/img/3.jpg b/img/normal.jpg similarity index 100% rename from img/3.jpg rename to img/normal.jpg diff --git a/img/3.jpg.html b/img/normal.jpg.full.html similarity index 72% rename from img/3.jpg.html rename to img/normal.jpg.full.html index 05d51bf..ea6fb9f 100644 --- a/img/3.jpg.html +++ b/img/normal.jpg.full.html @@ -10,9 +10,9 @@ display: block; } -
+
-
+
diff --git a/img/result.png b/img/result.png deleted file mode 100644 index d888a77..0000000 Binary files a/img/result.png and /dev/null differ diff --git a/package.json b/package.json index 57004d1..eaa2f31 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cquant", - "version": "0.0.19", + "version": "0.0.20", "description": "A fast and native image palette generator", "main": "cquant.js", "scripts": { diff --git a/src/async.cc b/src/async.cc index 3834f24..2b822eb 100644 --- a/src/async.cc +++ b/src/async.cc @@ -1,79 +1,80 @@ -#include #include "async.h" #include "colorquant.h" +#include class PaletteWorker : public Napi::AsyncWorker { public: - PaletteWorker(Napi::Function &callback, PIX *pix, int max_color) - : Napi::AsyncWorker(callback), - pix(pix), max_color(max_color), - counter(NULL), cmap(NULL) { - } - ~PaletteWorker() { - if (counter) { - free(counter); - } - if (cmap) { - if (cmap->array) { - free(cmap->array); - } - free(cmap); - } - if (pix) { - free(pix); - } - } - void Execute() { - counter = (size_t *)malloc(sizeof(size_t) * max_color); - cmap = pix_median_cut_quant(pix, max_color, 5, 0, counter); - } - void OnOK() { - Napi::HandleScope scope(Env()); + PaletteWorker(Napi::Function &callback, PIX *pix, int max_color, + int max_sub) + : Napi::AsyncWorker(callback), pix(pix), max_color(max_color), + counter(NULL), cmap(NULL), max_sub(max_sub) {} + ~PaletteWorker() { + if (counter) { + free(counter); + } + if (cmap) { + if (cmap->array) { + free(cmap->array); + } + free(cmap); + } + if (pix) { + free(pix); + } + } + void Execute() { + counter = (size_t *)malloc(sizeof(size_t) * max_color); + cmap = pix_median_cut_quant(pix, max_color, 5, max_sub, counter); + } + void OnOK() { + Napi::HandleScope scope(Env()); - if (cmap == NULL) { - auto err = Napi::Error::New(Env(), "Buffer corrupted or image too small or too less color"); - Callback().Call({ err.Value(), Env().Undefined() }); - return; - } + if (cmap == NULL) { + auto err = Napi::Error::New( + Env(), "Buffer corrupted or image too small or too less color"); + Callback().Call({err.Value(), Env().Undefined()}); + return; + } - Napi::Array result = Napi::Array::New(Env()); - RGB_QUAD *quad = (RGB_QUAD *)cmap->array; - for (size_t i = 0; i < cmap->n; i++) { - Napi::Object item = Napi::Object::New(Env()); - item.Set("R", quad[i].red); - item.Set("G", quad[i].green); - item.Set("B", quad[i].blue); - item.Set("count", counter[i]); - result.Set(i, item); - } - Callback().Call({ Env().Undefined(), result }); - } + Napi::Array result = Napi::Array::New(Env()); + RGB_QUAD *quad = (RGB_QUAD *)cmap->array; + for (size_t i = 0; i < cmap->n; i++) { + Napi::Object item = Napi::Object::New(Env()); + item.Set("R", quad[i].red); + item.Set("G", quad[i].green); + item.Set("B", quad[i].blue); + item.Set("count", counter[i]); + result.Set(i, item); + } + Callback().Call({Env().Undefined(), result}); + } private: - PIX *pix; - int max_color; - PIXCMAP *cmap; - size_t *counter; + PIX *pix; + int max_color; + PIXCMAP *cmap; + size_t *counter; + int max_sub; }; Napi::Value PaletteAsync(const Napi::CallbackInfo &info) { - auto depth = info[2].As().Int32Value(); - auto max_color = info[1].As().Int32Value(); + auto depth = info[2].As().Int32Value(); + auto max_color = info[1].As().Int32Value(); + auto max_sub = info[3].As().Int32Value(); - Napi::Function callback; - callback = info[3].As(); + Napi::Function callback; + callback = info[4].As(); - PIX *pix = (PIX *)malloc(sizeof(PIX)); - if (depth == 3) { - auto buffer = info[0].As>(); - pix->n = buffer.Length(); - pix->pixs = buffer.Data(); - } - else if (depth == 4) { - auto buffer = info[0].As>(); - pix->n = buffer.Length(); - pix->pixs = buffer.Data(); - } - pix->depth = depth; - PaletteWorker *paletteWorker = new PaletteWorker(callback, pix, max_color); - paletteWorker->Queue(); - return info.Env().Undefined(); + PIX *pix = (PIX *)malloc(sizeof(PIX)); + if (depth == 3) { + auto buffer = info[0].As>(); + pix->n = buffer.Length(); + pix->pixs = buffer.Data(); + } else if (depth == 4) { + auto buffer = info[0].As>(); + pix->n = buffer.Length(); + pix->pixs = buffer.Data(); + } + pix->depth = depth; + PaletteWorker *paletteWorker = new PaletteWorker(callback, pix, max_color, max_sub); + paletteWorker->Queue(); + return info.Env().Undefined(); } diff --git a/test/perf.js b/test/perf.js index 8776620..2391ddf 100644 --- a/test/perf.js +++ b/test/perf.js @@ -18,49 +18,51 @@ var pixels = require('image-pixels'); // cquant const sharp = require('sharp') const cquant = require('../cquant') -sharp('./img/0.jpg') +sharp('./img/large.1.jpg') .toBuffer((err, buffer, info) => { if (!err) { let start2 = Date.now() - cquant.paletteAsync(buffer, info.channels, 5, (_err, res) => { + cquant.paletteAsync(buffer, info.channels, 5, 0, (_err, res) => { if (!_err) { let time = Date.now() - start2; - console.log('cquant: 0.jpg 5572 x 3715 Time: ' + time + ' ms') + console.log(`cquant: large.1.jpg ${info.width} x ${info.height} Time: ${time} ms`) } }) } }); -// 3.jpg 1920 x 1280 -// image-palette -// (async () => { -// let start1 = Date.now(); -// let pixs = await pixels('./img/3.jpg') -// var { ids, colors } = palette(pixs) -// let time = Date.now() - start1 -// console.log('image-palette: 3.jpg 1920 x 1280 Time: ' + time + ' ms') -// })(); (function () { let start1 = Date.now(); - pixels('./img/3.jpg').then(pixs => { + pixels('./img/normal.jpg').then(pixs => { palette(pixs) let time = Date.now() - start1 - console.log('image-palette: 3.jpg 1920 x 1280 Time: ' + time + ' ms') + console.log(`image-palette: normal.jpg 1920 x 1280 Time: ${time} ms`) }).catch(err => { }) })(); // cquant -sharp('./img/3.jpg') +sharp('./img/normal.jpg') .toBuffer((err, buffer, info) => { if (!err) { let start2 = Date.now() - cquant.paletteAsync(buffer, info.channels, 5, (_err, res) => { + cquant.paletteAsync(buffer, info.channels, 5, 0, (_err, res) => { if (!_err) { let time = Date.now() - start2; - console.log('cquant: 3.jpg 1920 x 1280 Time: ' + time + ' ms') + console.log(`cquant: normal.jpg 1920 x 1280 Time: ${time} ms`) + } + }) + } + }); +sharp('./img/large.1.jpg') + .toBuffer((err, buffer, info) => { + if (!err) { + let start2 = Date.now() + cquant.paletteAsync(buffer, info.channels, 5, 1, (_err, res) => { + if (!_err) { + let time = Date.now() - start2; + console.log(`cquant: large.1.jpg ${info.width} x ${info.height} No SubSample Time: ${time} ms`) } }) } }); - // cquant with no sub_smaple // TODO: \ No newline at end of file diff --git a/test/test.js b/test/test.js index 6e40ad2..c9783b9 100644 --- a/test/test.js +++ b/test/test.js @@ -1,5 +1,6 @@ const cquant = require('../cquant') const fs = require('fs') +const path = require('path') const sharp = require('sharp') const stylePart = `