├── meson.build ├── README.md ├── .github └── workflows │ └── build.yaml └── autocrop.cpp /meson.build: -------------------------------------------------------------------------------- 1 | project('autocrop', 'cpp', 2 | default_options: ['buildtype=release', 'warning_level=2', 'b_lto=true', 'b_ndebug=if-release', 'cpp_std=c++11'], 3 | meson_version: '>=0.51.0', 4 | version: '1' 5 | ) 6 | 7 | cxx = meson.get_compiler('cpp') 8 | 9 | gcc_syntax = cxx.get_argument_syntax() == 'gcc' 10 | 11 | if gcc_syntax 12 | vapoursynth_dep = dependency('vapoursynth').partial_dependency(compile_args: true, includes: true) 13 | install_dir = vapoursynth_dep.get_variable(pkgconfig: 'libdir') / 'vapoursynth' 14 | else 15 | vapoursynth_dep = [] 16 | install_dir = get_option('libdir') / 'vapoursynth' 17 | endif 18 | 19 | sources = [ 20 | 'autocrop.cpp' 21 | ] 22 | 23 | shared_module('autocrop', sources, 24 | dependencies: vapoursynth_dep, 25 | install: true, 26 | install_dir: install_dir, 27 | gnu_symbol_visibility: 'hidden' 28 | ) 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vapoursynth-autocrop 2 | AutoCrop for Vapoursynth 3 | 4 | # Usage 5 | AutoCrop 6 | ```python 7 | acrop.AutoCrop(clip src, int range=4, int top=range, int bottom=range, int left=range, int right=range, int[] color=[0,123,123], int[] color_second=[21,133,133]) 8 | ``` 9 | 10 | Search only 11 | ```python 12 | acrop.CropValues(clip src, int range=4, int top=range, int bottom=range, int left=range, int right=range, int[] color=[0,123,123], int[] color_second=[21,133,133]) 13 | ``` 14 | 15 | ## Compilation 16 | 17 | ### Linux 18 | ``` 19 | g++ -std=c++11 -shared -fPIC -O2 autocrop.cpp -o libautocrop.so 20 | ``` 21 | 22 | ### Cross-compilation for Windows 23 | ``` 24 | x86_64-w64-mingw32-g++ -std=c++11 -shared -fPIC -O2 autocrop.cpp -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic -s -o autocrop.dll 25 | ``` 26 | 27 | 28 | # Thanks 29 | kageru, Attila, stux!, and Myrsloik 30 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | - push 4 | - release 5 | - pull_request 6 | - workflow_dispatch 7 | 8 | jobs: 9 | build: 10 | runs-on: windows-latest 11 | strategy: 12 | matrix: 13 | arch: 14 | - amd64 15 | - x86 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: setup MS dev commands 19 | uses: ilammy/msvc-dev-cmd@v1 20 | with: 21 | arch: ${{ matrix.arch }} 22 | - name: Setup Python 23 | uses: actions/setup-python@v1 24 | with: 25 | python-version: '3.x' 26 | - name: install meson and ninja 27 | run: pip install meson ninja 28 | 29 | - name: download VS headers and patch header location 30 | shell: bash 31 | run: | 32 | git clone https://github.com/AmusementClub/vapoursynth-classic --depth=1 --branch doodle2 vapoursynth 33 | cp vapoursynth/include/*.h . 34 | - name: Meson setup 35 | run: meson setup builddir/ -Db_vscrt=mt 36 | - name: Meson compile 37 | run: meson compile -C builddir/ -v 38 | - name: Upload artifact 39 | uses: actions/upload-artifact@v2 40 | with: 41 | name: release-${{matrix.arch}} 42 | path: | 43 | builddir/*.dll 44 | -------------------------------------------------------------------------------- /autocrop.cpp: -------------------------------------------------------------------------------- 1 | #include "VapourSynth.h" 2 | #include "VSHelper.h" 3 | #include 4 | #define SET_COLOR_RESAMPLE 0x0000001 5 | #define setBlack(color, format) {uint32_t b1[3] = {0, 123, 123}; setColor(color, format, b1, SET_COLOR_RESAMPLE);} 6 | #define setBlack2(color, format) {uint32_t b2[3] = {21, 133, 133}; setColor(color, format, b2, SET_COLOR_RESAMPLE);} 7 | #define setColorSimple(color, format, base) setColor(color, format, base, SET_COLOR_RESAMPLE); 8 | #define OUT 9 | #define IN 10 | 11 | typedef struct { 12 | VSNodeRef *node; 13 | const VSVideoInfo *vi_finish; 14 | const VSVideoInfo *vi; 15 | int range; 16 | int top; 17 | int bottom; 18 | int left; 19 | int right; 20 | uint32_t color[3]; 21 | uint32_t color_second[3]; 22 | } AutoCropData; 23 | 24 | struct CropPlaneValues { 25 | int topArray[3]; 26 | int bottomArray[3]; 27 | int leftArray[3]; 28 | int rightArray[3]; 29 | }; 30 | 31 | struct CropFrameValues { 32 | int top; 33 | int bottom; 34 | int left; 35 | int right; 36 | int width; 37 | int height; 38 | }; 39 | 40 | inline void setColor(OUT uint32_t color[3], const IN VSFormat *format, IN uint32_t base[3], int flags=0) { 41 | if (flags & SET_COLOR_RESAMPLE && format->sampleType == stInteger) { 42 | for (int i = 0; i<3; i++) 43 | base[i] <<= (format->bitsPerSample - 8); 44 | } 45 | 46 | for (int i = 0; i < 3; i++) 47 | color[i] = base[i]; 48 | } 49 | 50 | int checkSubSampling(int cropValueArray[3], int subSampling){ 51 | int cropValue; 52 | 53 | cropValue = std::min(std::min(cropValueArray[0], cropValueArray[1] << subSampling), cropValueArray[2] << subSampling); 54 | cropValue = cropValue - (cropValue % (1 << subSampling)); 55 | 56 | return cropValue; 57 | } 58 | 59 | template 60 | void getCropValues(CropPlaneValues *c, const Bit *srcp, int src_stride, int w, int h, int color, int color2, 61 | int topRange, int bottomRange, int leftRange, int rightRange, int plane) { 62 | int topValue = 0; 63 | int bottomValue = bottomRange; 64 | int leftValue = leftRange; 65 | int rightValue = rightRange; 66 | for (int y = 0; y < h; y++) { 67 | //top 68 | if (y < topRange) { 69 | for (int x = 0; x < w; x += 10) { 70 | if (!(color <= srcp[x] && srcp[x] <= color2)) { 71 | topRange = 0; 72 | break; 73 | } 74 | } 75 | if (topRange) { 76 | topValue++; 77 | } 78 | } 79 | //left 80 | for (int x = 0; x < leftRange; x++) { 81 | if (!(color <= srcp[x] && srcp[x] <= color2)) { 82 | if (leftValue >= x) { 83 | leftValue = x; 84 | } 85 | } 86 | } 87 | //right 88 | for (int x = w - rightRange; x < w; x++) { 89 | if (!(color <= srcp[x] && srcp[x] <= color2)) { 90 | if (rightValue >= w - x) { 91 | rightValue = w - x - 1; 92 | } 93 | } 94 | } 95 | //bottom 96 | if (y >= h - bottomRange) { 97 | for (int x = 0; x < w; x += 10) { 98 | if (!(color <= srcp[x] && srcp[x] <= color2)) { 99 | bottomValue = h - (y + 1); 100 | break; 101 | } 102 | } 103 | } 104 | srcp += src_stride; 105 | } 106 | 107 | c->topArray[plane] = topValue; 108 | c->bottomArray[plane] = bottomValue; 109 | c->leftArray[plane] = leftValue; 110 | c->rightArray[plane] = rightValue; 111 | } 112 | 113 | template 114 | void getFramePlane(const VSFrameRef *src, AutoCropData *data, const VSAPI *vsapi, CropFrameValues *cFrame) { 115 | CropPlaneValues cPlane{}; 116 | const VSFormat *fi = data->vi->format; 117 | 118 | for (int plane = 0; plane < fi->numPlanes; plane++) { 119 | const auto *srcp = (const Bit *) vsapi->getReadPtr(src, plane); 120 | int src_stride = vsapi->getStride(src, plane) / sizeof(Bit); 121 | int h = vsapi->getFrameHeight(src, plane); 122 | int w = vsapi->getFrameWidth(src, plane); 123 | 124 | if (plane == 0){ 125 | getCropValues(&cPlane, srcp, src_stride, w, h, data->color[0], data->color_second[0], data->top, 126 | data->bottom, data->left, data->right, plane); 127 | } 128 | else if(plane == 1){ 129 | if (data->vi->format->subSamplingH == 0 && data->vi->format->subSamplingW == 0) { 130 | getCropValues(&cPlane, srcp, src_stride, w, h, data->color[1], data->color_second[1], data->top, 131 | data->bottom, data->left, data->right, plane); 132 | } 133 | else if (data->vi->format->subSamplingH == 1 && data->vi->format->subSamplingW == 1) { 134 | getCropValues(&cPlane, srcp, src_stride, w, h, data->color[1], data->color_second[1], data->top/2, 135 | data->bottom/2, data->left/2, data->right/2, plane); 136 | } 137 | } 138 | else { 139 | if (data->vi->format->subSamplingH == 0 && data->vi->format->subSamplingW == 0) { 140 | getCropValues(&cPlane, srcp, src_stride, w, h, data->color[2], data->color_second[2], data->top, 141 | data->bottom, data->left, data->right, plane); 142 | } 143 | else if (data->vi->format->subSamplingH == 1 && data->vi->format->subSamplingW == 1){ 144 | getCropValues(&cPlane, srcp, src_stride, w, h, data->color[2], data->color_second[2], data->top/2, 145 | data->bottom/2, data->left/2, data->right/2, plane); 146 | } 147 | } 148 | } 149 | 150 | cFrame->top = checkSubSampling(cPlane.topArray, data->vi->format->subSamplingH); 151 | cFrame->bottom = checkSubSampling(cPlane.bottomArray, data->vi->format->subSamplingH); 152 | cFrame->left = checkSubSampling(cPlane.leftArray, data->vi->format->subSamplingW); 153 | cFrame->right = checkSubSampling(cPlane.rightArray, data->vi->format->subSamplingW); 154 | cFrame->height = data->vi->height - cFrame->top - cFrame->bottom; 155 | cFrame->width = data->vi->width - cFrame->left - cFrame->right; 156 | } 157 | 158 | ///////////////// 159 | // CropValues 160 | 161 | static void VS_CC cropValuesInit(VSMap *in, VSMap *out, void **instanceData, VSNode *node, VSCore *core, const VSAPI *vsapi) { 162 | auto *data = (AutoCropData *) * instanceData; 163 | VSVideoInfo vi_finish = *data->vi_finish; 164 | vsapi->setVideoInfo(&vi_finish, 1, node); 165 | } 166 | 167 | static const VSFrameRef *VS_CC cropValuesGetFrame(int n, int activationReason, void **instanceData, void **frameData, 168 | VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi) { 169 | auto *data = (AutoCropData *) * instanceData; 170 | const char *top = "CropTopValue"; 171 | const char *bottom = "CropBottomValue"; 172 | const char *left = "CropLeftValue"; 173 | const char *right = "CropRightValue"; 174 | 175 | if (activationReason == arInitial) { 176 | vsapi->requestFrameFilter(n, data->node, frameCtx); 177 | } 178 | else if (activationReason == arAllFramesReady) { 179 | const VSFrameRef *src = vsapi->getFrameFilter(n, data->node, frameCtx); 180 | const VSFormat *fi = data->vi->format; 181 | CropFrameValues cFrame{}; 182 | 183 | if (data->vi->format->sampleType == stInteger && data->vi->format->bitsPerSample == 8) { 184 | getFramePlane(src, data, vsapi, &cFrame); 185 | } else if (data->vi->format->sampleType == stInteger && data->vi->format->bitsPerSample <= 16){ 186 | getFramePlane(src, data, vsapi, &cFrame); 187 | } 188 | 189 | VSFrameRef *dst = vsapi->copyFrame(src, core); 190 | for (int plane = 0; plane < fi->numPlanes; plane++) { 191 | vsapi->getWritePtr(dst, plane); 192 | } 193 | 194 | VSMap *dstProps = vsapi->getFramePropsRW(dst); 195 | 196 | if (fi->sampleType == stInteger) { 197 | vsapi->propSetInt(dstProps, top, cFrame.top, paAppend); 198 | vsapi->propSetInt(dstProps, bottom, cFrame.bottom, paAppend); 199 | vsapi->propSetInt(dstProps, left, cFrame.left, paAppend); 200 | vsapi->propSetInt(dstProps, right, cFrame.right, paAppend); 201 | } 202 | vsapi->freeFrame(src); 203 | 204 | return dst; 205 | } 206 | 207 | return 0; 208 | } 209 | 210 | static void VS_CC cropValuesFree(void *instanceData, VSCore *core, const VSAPI *vsapi) { 211 | auto *data = (AutoCropData *)instanceData; 212 | vsapi->freeNode(data->node); 213 | free(data); 214 | } 215 | 216 | static void VS_CC cropValuesCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { 217 | AutoCropData d; 218 | AutoCropData *data; 219 | int err; 220 | 221 | d.node = vsapi->propGetNode(in, "clip", 0, 0); 222 | d.vi_finish = vsapi->getVideoInfo(d.node); 223 | d.vi = vsapi->getVideoInfo(d.node); 224 | 225 | if (!isConstantFormat(d.vi) || d.vi->format->sampleType != stInteger || d.vi->format->bitsPerSample < 8 || d.vi->format->bitsPerSample > 16) { 226 | vsapi->setError(out, "CropValues: only constant format 8...16Bit integer input supported"); 227 | vsapi->freeNode(d.node); 228 | return; 229 | } 230 | 231 | if (!(d.vi->format->colorFamily == cmYCoCg || d.vi->format->colorFamily == cmYUV)){ 232 | vsapi->setError(out, "CropValues: only YUV or YCoCg input supported"); 233 | vsapi->freeNode(d.node); 234 | return; 235 | } 236 | 237 | d.range = int64ToIntS(vsapi->propGetInt(in, "range", 0, &err)); 238 | if (err) 239 | d.range = 4; 240 | 241 | d.top = int64ToIntS(vsapi->propGetInt(in, "top", 0, &err)); 242 | if (err) 243 | d.top = d.range; 244 | 245 | d.bottom = int64ToIntS(vsapi->propGetInt(in, "bottom", 0, &err)); 246 | if (err) 247 | d.bottom = d.range; 248 | 249 | d.right = int64ToIntS(vsapi->propGetInt(in, "right", 0, &err)); 250 | if (err) 251 | d.right = d.range; 252 | 253 | d.left = int64ToIntS(vsapi->propGetInt(in, "left", 0, &err)); 254 | if (err) 255 | d.left = d.range; 256 | 257 | if (d.vi->format->subSamplingH == 1 && d.vi->format->subSamplingW == 1){ 258 | if (d.range&1 || d.left&1 || d.right&1 || d.top&1 || d.bottom&1) { 259 | vsapi->setError(out, "CropValues: Odd numbers for Crop not allowed"); 260 | vsapi->freeNode(d.node); 261 | return; 262 | } 263 | } 264 | 265 | if (d.range < 0 || d.left < 0 || d.right < 0 || d.top < 0 || d.bottom < 0) { 266 | vsapi->setError(out, "AutoCrop: Negative numbers for crop not allowed"); 267 | vsapi->freeNode(d.node); 268 | return; 269 | } 270 | 271 | uint32_t color_base[3]; 272 | uint32_t color_base1[3]; 273 | int numcomponents = (d.vi->format->colorFamily == cmCompat) ? 3 : d.vi->format->numPlanes; 274 | int ncolors = vsapi->propNumElements(in, "color"); 275 | int ncolors1 = vsapi->propNumElements(in, "color_second"); 276 | 277 | if (ncolors == numcomponents) { 278 | for (int i = 0; i < ncolors; i++) { 279 | color_base[i] = static_cast(vsapi->propGetInt(in, "color", i, 0)); 280 | } 281 | setColorSimple(d.color, d.vi->format, color_base); 282 | } 283 | else{ 284 | setBlack(d.color, d.vi->format); 285 | } 286 | 287 | if (ncolors1 == numcomponents) { 288 | for (int i = 0; i < ncolors1; i++) { 289 | color_base1[i] = static_cast(vsapi->propGetInt(in, "color_second", i, 0)); 290 | } 291 | setColorSimple(d.color_second, d.vi->format, color_base1); 292 | } 293 | else{ 294 | setBlack2(d.color_second, d.vi->format); 295 | } 296 | 297 | data = static_cast(malloc(sizeof(d))); 298 | *data = d; 299 | 300 | vsapi->createFilter(in, out, "CropValues", cropValuesInit, cropValuesGetFrame, cropValuesFree, fmParallel, 0, data, core); 301 | } 302 | 303 | ///////////////// 304 | // AutoCrop 305 | 306 | static void VS_CC autocropInit(VSMap *in, VSMap *out, void **instanceData, VSNode *node, VSCore *core, const VSAPI *vsapi) { 307 | auto *data = (AutoCropData *) * instanceData; 308 | VSVideoInfo vi_finish = *data->vi_finish; 309 | vi_finish.height = 0; 310 | vi_finish.width = 0; 311 | vsapi->setVideoInfo(&vi_finish, 1, node); 312 | } 313 | 314 | static const VSFrameRef *VS_CC autocropGetFrame(int n, int activationReason, void **instanceData, void **frameData, 315 | VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi) { 316 | auto *data = (AutoCropData *) * instanceData; 317 | 318 | if (activationReason == arInitial) { 319 | vsapi->requestFrameFilter(n, data->node, frameCtx); 320 | } else if (activationReason == arAllFramesReady) { 321 | const VSFrameRef *src = vsapi->getFrameFilter(n, data->node, frameCtx); 322 | const VSFormat *fi = data->vi->format; 323 | CropFrameValues cFrame{}; 324 | 325 | if (data->vi->format->sampleType == stInteger && data->vi->format->bitsPerSample == 8) { 326 | getFramePlane(src, data, vsapi, &cFrame); 327 | } else if (data->vi->format->sampleType == stInteger && data->vi->format->bitsPerSample <= 16){ 328 | getFramePlane(src, data, vsapi, &cFrame); 329 | } 330 | 331 | //from https://github.com/vapoursynth/vapoursynth/blob/738f2be63b8d2b19c73b5e20116058f12f9b278d/src/core/simplefilters.c#L132 332 | VSFrameRef *dst_finish = vsapi->newVideoFrame(fi, cFrame.width, cFrame.height, src, core); 333 | for (int plane_new = 0; plane_new < fi->numPlanes; plane_new++) { 334 | int srcstride = vsapi->getStride(src, plane_new); 335 | int dststride = vsapi->getStride(dst_finish, plane_new); 336 | const uint8_t *srcdata = vsapi->getReadPtr(src, plane_new); 337 | uint8_t *dstdata = vsapi->getWritePtr(dst_finish, plane_new); 338 | srcdata += srcstride * (cFrame.top >> (plane_new ? fi->subSamplingH : 0)); 339 | srcdata += (cFrame.left >> (plane_new ? fi->subSamplingW : 0)) * fi->bytesPerSample; 340 | vs_bitblt(dstdata, dststride, srcdata, srcstride, 341 | (cFrame.width >> (plane_new ? fi->subSamplingW : 0)) * fi->bytesPerSample, 342 | vsapi->getFrameHeight(dst_finish, plane_new)); 343 | } 344 | vsapi->freeFrame(src); 345 | 346 | return dst_finish; 347 | } 348 | 349 | return 0; 350 | } 351 | 352 | static void VS_CC autocropFree(void *instanceData, VSCore *core, const VSAPI *vsapi) { 353 | auto *data = (AutoCropData *)instanceData; 354 | vsapi->freeNode(data->node); 355 | free(data); 356 | } 357 | 358 | static void VS_CC autocropCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { 359 | AutoCropData d; 360 | AutoCropData *data; 361 | uint32_t color_base[3]; 362 | uint32_t color_base1[3]; 363 | int err; 364 | 365 | d.node = vsapi->propGetNode(in, "clip", 0, 0); 366 | d.vi_finish = vsapi->getVideoInfo(d.node); 367 | d.vi = vsapi->getVideoInfo(d.node); 368 | 369 | if (!isConstantFormat(d.vi) || d.vi->format->sampleType != stInteger || d.vi->format->bitsPerSample < 8 || d.vi->format->bitsPerSample > 16) { 370 | vsapi->setError(out, "AutoCrop: only constant format 8...16Bit integer input supported"); 371 | vsapi->freeNode(d.node); 372 | return; 373 | } 374 | 375 | if (!(d.vi->format->colorFamily == cmYCoCg || d.vi->format->colorFamily == cmYUV)){ 376 | vsapi->setError(out, "AutoCrop: only YUV or YCoCg input supported"); 377 | vsapi->freeNode(d.node); 378 | return; 379 | } 380 | 381 | d.range = int64ToIntS(vsapi->propGetInt(in, "range", 0, &err)); 382 | if (err) 383 | d.range = 4; 384 | 385 | d.top = int64ToIntS(vsapi->propGetInt(in, "top", 0, &err)); 386 | if (err) 387 | d.top = d.range; 388 | 389 | d.bottom = int64ToIntS(vsapi->propGetInt(in, "bottom", 0, &err)); 390 | if (err) 391 | d.bottom = d.range; 392 | 393 | d.right = int64ToIntS(vsapi->propGetInt(in, "right", 0, &err)); 394 | if (err) 395 | d.right = d.range; 396 | 397 | d.left = int64ToIntS(vsapi->propGetInt(in, "left", 0, &err)); 398 | if (err) 399 | d.left = d.range; 400 | 401 | if (d.vi->format->subSamplingH == 1 && d.vi->format->subSamplingW == 1){ 402 | if (d.range&1 || d.left&1 || d.right&1 || d.top&1 || d.bottom&1) { 403 | vsapi->setError(out, "AutoCrop: Odd numbers for crop not allowed"); 404 | vsapi->freeNode(d.node); 405 | return; 406 | } 407 | } 408 | 409 | if (d.range < 0 || d.left < 0 || d.right < 0 || d.top < 0 || d.bottom < 0) { 410 | vsapi->setError(out, "AutoCrop: Negative numbers for crop not allowed"); 411 | vsapi->freeNode(d.node); 412 | return; 413 | } 414 | 415 | int numcomponents = (d.vi->format->colorFamily == cmCompat) ? 3 : d.vi->format->numPlanes; 416 | int ncolors = vsapi->propNumElements(in, "color"); 417 | int ncolors1 = vsapi->propNumElements(in, "color_second"); 418 | 419 | if (ncolors == numcomponents) { 420 | for (int i = 0; i < ncolors; i++) { 421 | color_base[i] = static_cast(vsapi->propGetInt(in, "color", i, 0)); 422 | } 423 | setColorSimple(d.color, d.vi->format, color_base); 424 | } 425 | else{ 426 | setBlack(d.color, d.vi->format); 427 | } 428 | 429 | if (ncolors1 == numcomponents) { 430 | for (int i = 0; i < ncolors1; i++) { 431 | color_base1[i] = static_cast(vsapi->propGetInt(in, "color_second", i, 0)); 432 | } 433 | setColorSimple(d.color_second, d.vi->format, color_base1); 434 | } 435 | else{ 436 | setBlack2(d.color_second, d.vi->format); 437 | } 438 | data = static_cast(malloc(sizeof(d))); 439 | *data = d; 440 | 441 | vsapi->createFilter(in, out, "AutoCrop", autocropInit, autocropGetFrame, autocropFree, fmParallel, 0, data, core); 442 | } 443 | 444 | ////////////////////////////////////////// 445 | // Init 446 | 447 | VS_EXTERNAL_API(void) VapourSynthPluginInit(VSConfigPlugin configFunc, VSRegisterFunction registerFunc, VSPlugin *plugin) { 448 | configFunc("moe.infi.autocrop", "acrop", "VapourSynth AutoCrop", VAPOURSYNTH_API_VERSION, 1, plugin); 449 | registerFunc("AutoCrop", "clip:clip;range:int:opt;top:int:opt;bottom:int:opt;left:int:opt;right:int:opt;color:int[]:opt;color_second:int[]:opt", autocropCreate, 0, plugin); 450 | registerFunc("CropValues", "clip:clip;range:int:opt;top:int:opt;bottom:int:opt;left:int:opt;right:int:opt;color:int[]:opt;color_second:int[]:opt", cropValuesCreate, 0, plugin); 451 | } 452 | --------------------------------------------------------------------------------