├── .gitignore ├── usage.gif ├── .vscodeignore ├── .eslintrc.json ├── src ├── test │ ├── suite │ │ ├── extension.test.ts │ │ └── index.ts │ └── runTest.ts ├── ViewImageService.ts └── extension.ts ├── tsconfig.json ├── LICENSE ├── CHANGELOG.md ├── webpack.config.js ├── package.json ├── vsc-extension-quickstart.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /out/ 2 | /node_modules/ 3 | /dist/ 4 | *.vsix -------------------------------------------------------------------------------- /usage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/john-guo/simply-view-image-for-python-opencv-debugging/HEAD/usage.gif -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/** 4 | src/** 5 | .gitignore 6 | vsc-exdtension-quickstart.md 7 | **/tsconfig.json 8 | **/.eslintrc.json 9 | **/*.map 10 | **/*.ts 11 | webpack.config.js -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/class-name-casing": "warn", 13 | "@typescript-eslint/semi": "warn", 14 | "curly": "warn", 15 | "eqeqeq": "warn", 16 | "no-throw-literal": "warn", 17 | "semi": "off" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | import * as vscode from 'vscode'; 6 | // import * as myExtension from '../extension'; 7 | 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.equal(-1, [1, 2, 3].indexOf(5)); 13 | assert.equal(-1, [1, 2, 3].indexOf(0)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | }, 17 | "exclude": [ 18 | "node_modules", 19 | ".vscode-test" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from 'vscode-test'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to test runner 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | color: true 10 | }); 11 | 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | 14 | return new Promise((c, e) => { 15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 16 | if (err) { 17 | return e(err); 18 | } 19 | 20 | // Add files to the test suite 21 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 22 | 23 | try { 24 | // Run the mocha test 25 | mocha.run(failures => { 26 | if (failures > 0) { 27 | e(new Error(`${failures} tests failed.`)); 28 | } else { 29 | c(); 30 | } 31 | }); 32 | } catch (err) { 33 | console.error(err); 34 | e(err); 35 | } 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2022 John Guo guoyichao@hotmail.com 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "simply-view-image-for-python-opencv-debugging" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [0.0.11] 8 | - Fix an issue, use the globalStorageUri.fsPath instead of globalStorageUri.path. 9 | 10 | ## [0.0.10] 11 | 12 | - Add "onDebugResolve:debugpy" to package.json (activationEvents) 13 | - Compatibility with registerCodeActionsProvider (use DocumentSelector instead of string) 14 | 15 | ## [0.0.9] 16 | 17 | - Add tf2 tensor support. 18 | 19 | ## [0.0.8] 20 | 21 | - Now the global variables can be view. 22 | 23 | ## [0.0.7] 24 | 25 | - Using a workaround for supporting multithreading. 26 | 27 | ## [0.0.6] 28 | 29 | - Add an option "svifpod.usetmppathtosave" to choose which path (tmp or extenion private storage path) to save, default is tmp path. 30 | 31 | ## [0.0.5] 32 | 33 | - Add a command "View Image(Python OpenCV Debug)". 34 | - Add a keyboard shortcut "ctrl+alt+Q" for quickly image viewing. 35 | 36 | ## [0.0.4] 37 | 38 | - Add ndarray checking to avoid some exceptions. 39 | 40 | ## [0.0.3] 41 | 42 | - Update README.md 43 | 44 | ## [0.0.2] 45 | 46 | - Thanks to [marisancans](https://github.com/marisancans) add support for float np array. 47 | 48 | ## [0.0.1] 49 | 50 | - Initial release 51 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | //@ts-check 2 | 3 | 'use strict'; 4 | 5 | const path = require('path'); 6 | 7 | /**@type {import('webpack').Configuration}*/ 8 | const config = { 9 | target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ 10 | 11 | entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ 12 | output: { 13 | // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ 14 | path: path.resolve(__dirname, 'dist'), 15 | filename: 'extension.js', 16 | libraryTarget: 'commonjs2', 17 | devtoolModuleFilenameTemplate: '../[resource-path]' 18 | }, 19 | devtool: 'source-map', 20 | externals: { 21 | vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ 22 | }, 23 | resolve: { 24 | // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader 25 | extensions: ['.ts', '.js'] 26 | }, 27 | module: { 28 | rules: [ 29 | { 30 | test: /\.ts$/, 31 | exclude: /node_modules/, 32 | use: [ 33 | { 34 | loader: 'ts-loader' 35 | } 36 | ] 37 | } 38 | ] 39 | } 40 | }; 41 | module.exports = config; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simply-view-image-for-python-opencv-debugging", 3 | "displayName": "simply_view_image_for_python_opencv_debugging", 4 | "description": "simply view the image of the image variables when debugging python with opencv", 5 | "version": "0.0.11", 6 | "publisher": "johnguo", 7 | "engines": { 8 | "vscode": "^1.86.1" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/john-guo/simply-view-image-for-python-opencv-debugging" 13 | }, 14 | "categories": [ 15 | "Other" 16 | ], 17 | "activationEvents": [ 18 | "onDebugResolve:python", 19 | "onDebugResolve:debugpy" 20 | ], 21 | "main": "./dist/extension.js", 22 | "contributes": { 23 | "commands": [ 24 | { 25 | "command": "extension.viewimagepythonopencvdebug", 26 | "title": "View Image(Python OpenCV Debug)", 27 | "enablement": "inDebugMode" 28 | } 29 | ], 30 | "keybindings": [ 31 | { 32 | "command": "extension.viewimagepythonopencvdebug", 33 | "key": "ctrl+alt+q", 34 | "when": "inDebugMode" 35 | } 36 | ], 37 | "configuration": { 38 | "title": "View Image(Python OpenCV Debug)", 39 | "properties": { 40 | "svifpod.usetmppathtosave": { 41 | "type": "boolean", 42 | "default": true, 43 | "description": "Use the system tmp path to save image otherwise use the storage path." 44 | } 45 | } 46 | } 47 | }, 48 | "scripts": { 49 | "vscode:prepublish": "webpack --mode production", 50 | "webpack": "webpack --mode development", 51 | "webpack-dev": "webpack --mode development --watch", 52 | "test-compile": "tsc -p ./", 53 | "compile": "tsc -p ./", 54 | "lint": "eslint src --ext ts", 55 | "watch": "tsc -watch -p ./", 56 | "pretest": "npm run compile && npm run lint", 57 | "test": "node ./out/test/runTest.js" 58 | }, 59 | "devDependencies": { 60 | "@types/glob": "^7.1.4", 61 | "@types/mocha": "^7.0.2", 62 | "@types/node": "^13.13.52", 63 | "@types/vscode": "^1.60.0", 64 | "@typescript-eslint/eslint-plugin": "^5.9.1", 65 | "@typescript-eslint/parser": "^5.9.1", 66 | "eslint": "^8.6.0", 67 | "glob": "^7.1.7", 68 | "mocha": "^11.1.0", 69 | "set-value": ">=4.0.1", 70 | "ts-loader": "^9.4.2", 71 | "typescript": "^3.9.10", 72 | "vscode-test": "^1.6.1", 73 | "webpack": "^5.94.0", 74 | "webpack-cli": "^4.9.1" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/ViewImageService.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { join } from 'path'; 3 | 4 | export default class ViewImageService { 5 | private workingdir :string; 6 | 7 | public constructor(dir: string) 8 | { 9 | this.workingdir = dir; 10 | } 11 | 12 | public async ViewImage(document: vscode.TextDocument, range: vscode.Range): Promise { 13 | const session = vscode.debug.activeDebugSession; 14 | if (session === undefined) { 15 | return; 16 | } 17 | 18 | const selectedVariable = document.getText(document.getWordRangeAtPosition(range.start)); 19 | 20 | let res = await session.customRequest('threads', {}); 21 | let threads = res.threads; 22 | let variables : any[] = []; 23 | let targetVariable = undefined; 24 | let callStack = 0; 25 | 26 | end: 27 | for (const thread of threads) 28 | { 29 | res = await session.customRequest('stackTrace', { threadId: thread.id }); 30 | let stacks = res.stackFrames; 31 | for (let stack of stacks) 32 | { 33 | callStack = stack.id 34 | res = await session.customRequest('scopes', {frameId: callStack}); 35 | let scopes = res.scopes; 36 | for (let scope of scopes) 37 | { 38 | res = await session.customRequest('variables', {variablesReference: scope.variablesReference}); 39 | variables = res.variables; 40 | targetVariable = variables.find( v => v.name === selectedVariable); 41 | if (targetVariable !== undefined) 42 | { 43 | break end; 44 | } 45 | } 46 | } 47 | } 48 | 49 | if (targetVariable === undefined) 50 | { 51 | return; 52 | } 53 | 54 | let path = join(this.workingdir, `${targetVariable.name}.png`); 55 | let savepath = path.replace(/\\/g, '/'); 56 | 57 | const vn = targetVariable.evaluateName; // var name 58 | const nparray_expression = `(${vn}.numpy() * 255.0 if (hasattr(${vn}, 'dtype')) and (${vn}.dtype == np.float64 or ${vn}.dtype == np.float32) else ${vn}.numpy()) if callable(getattr(${vn}, 'numpy', None)) else (${vn} * 255.0 if (isinstance(${vn}, (np.ndarray)) and (${vn}.dtype == np.float64 or ${vn}.dtype == np.float32)) else ${vn})`; 59 | const expression = `cv2.imwrite('${savepath}', ${nparray_expression})`; 60 | res = await session.customRequest("evaluate", { expression: expression, frameId: callStack, context:'hover' }); 61 | console.log(`evaluate ${expression} result: ${res.result}`); 62 | 63 | return path; 64 | } 65 | } -------------------------------------------------------------------------------- /vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | 5 | * This folder contains all of the files necessary for your extension. 6 | * `package.json` - this is the manifest file in which you declare your extension and command. 7 | * The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. 8 | * `src/extension.ts` - this is the main file where you will provide the implementation of your command. 9 | * The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. 10 | * We pass the function containing the implementation of the command as the second parameter to `registerCommand`. 11 | 12 | ## Get up and running straight away 13 | 14 | * Press `F5` to open a new window with your extension loaded. 15 | * Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. 16 | * Set breakpoints in your code inside `src/extension.ts` to debug your extension. 17 | * Find output from your extension in the debug console. 18 | 19 | ## Make changes 20 | 21 | * You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`. 22 | * You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 23 | 24 | 25 | ## Explore the API 26 | 27 | * You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. 28 | 29 | ## Run tests 30 | 31 | * Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`. 32 | * Press `F5` to run the tests in a new window with your extension loaded. 33 | * See the output of the test result in the debug console. 34 | * Make changes to `src/test/suite/extension.test.ts` or create new test files inside the `test/suite` folder. 35 | * The provided test runner will only consider files matching the name pattern `**.test.ts`. 36 | * You can create folders inside the `test` folder to structure your tests any way you want. 37 | 38 | ## Go further 39 | 40 | * Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension). 41 | * [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace. 42 | * Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration). 43 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | // The module 'vscode' contains the VS Code extensibility API 2 | // Import the module and reference it with the alias vscode in your code below 3 | import * as vscode from 'vscode'; 4 | import ViewImageService from './ViewImageService'; 5 | import { tmpdir } from 'os'; 6 | import { mkdirSync, existsSync, readdirSync, unlinkSync } from 'fs'; 7 | import { join } from 'path'; 8 | 9 | let viewImageSvc: ViewImageService; 10 | 11 | const WORKING_DIR = 'svifpod'; 12 | 13 | // this method is called when your extension is activated 14 | // your extension is activated the very first time the command is executed 15 | export function activate(context: vscode.ExtensionContext) { 16 | let usetmp = vscode.workspace.getConfiguration("svifpod").get("usetmppathtosave", true); 17 | let dir = context.globalStorageUri.fsPath as string; 18 | if (usetmp || dir === undefined) 19 | { 20 | dir = tmpdir(); 21 | dir = join(dir, WORKING_DIR); 22 | } 23 | 24 | if (existsSync(dir)) 25 | { 26 | let files = readdirSync(dir); 27 | files.forEach(file => { 28 | let curPath = join(dir, file); 29 | unlinkSync(curPath); 30 | }); 31 | } 32 | else 33 | { 34 | mkdirSync(dir); 35 | } 36 | 37 | viewImageSvc = new ViewImageService(dir); 38 | 39 | // Use the console to output diagnostic information (console.log) and errors (console.error) 40 | // This line of code will only be executed once when your extension is activated 41 | console.log('Congratulations, your extension "simply-view-image-for-python-opencv-debugging" is now active!'); 42 | 43 | context.subscriptions.push( 44 | vscode.languages.registerCodeActionsProvider({ scheme: 'file', language: 'python' }, 45 | new PythonOpencvImageProvider(), { providedCodeActionKinds: [vscode.CodeActionKind.Empty] })); 46 | 47 | 48 | context.subscriptions.push( 49 | vscode.commands.registerTextEditorCommand("extension.viewimagepythonopencvdebug", async editor => { 50 | let path = await viewImageSvc.ViewImage(editor.document, editor.selection); 51 | if (path === undefined) { 52 | return; 53 | } 54 | vscode.commands.executeCommand("vscode.open", vscode.Uri.file(path), vscode.ViewColumn.Beside); 55 | }) 56 | ); 57 | 58 | } 59 | 60 | // this method is called when your extension is deactivated 61 | export function deactivate() {} 62 | 63 | 64 | /** 65 | * Provides code actions for python opencv image. 66 | */ 67 | export class PythonOpencvImageProvider implements vscode.CodeActionProvider { 68 | 69 | public async provideCodeActions(document: vscode.TextDocument, range: vscode.Range): Promise { 70 | 71 | let path = await viewImageSvc.ViewImage(document, range); 72 | if (path === undefined) { 73 | return; 74 | } 75 | 76 | return [ 77 | { command:"vscode.open", title: 'View Image', arguments: [ vscode.Uri.file(path), vscode.ViewColumn.Beside ] } 78 | ]; 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # simply-view-image-for-python-opencv-debugging README 2 | 3 | ## Features 4 | 5 | This simple extension can and **only** can let you view the image of a variable when you are debugging **python** codes with **opencv**. 6 | 7 | Currently, It's only support python with opencv module *(opencv-python)* debugging. 8 | 9 | There is a limition that's your python codes must import opencv as cv2 and import numpy as np. 10 | 11 | For example: 12 | 13 | import cv2 14 | import numpy as np 15 | 16 | ## Requirements 17 | 18 | Python debugger extension for vscode (vscode Microsoft official python extension recommend) 19 | 20 | Python module of OpenCV support **imwrite** function installed (official module *opencv-python* recommend) 21 | 22 | ## How to use 23 | 24 | Due to vscode do not allow extension customizes hover when you are debugging so that this extension use the code action command to open a new editor to view the image. 25 | 26 | Since 0.0.5 add a command "View Image(Python OpenCV Debug)" and a keybord shortcut "ctrl+alt+q" to open the image. 27 | 28 | ### Step 29 | 30 | 1. Open a python file which has "import cv2". 31 | 32 | 2. Start Debug 33 | 34 | 3. Break on a certain line 35 | 36 | 4. Click a variable that contains image data and waiting for the code action icon (a little yellow light bubble) popup. 37 | 38 | 5. Click the icon or press ctrl+. to popup a menu then click the menu to view image. 39 | 40 | ![How to use](usage.gif) 41 | 42 | ## Extension Settings 43 | 44 | No settings, the initail version is hardcode. 45 | 46 | ## Limitations 47 | 48 | The initail version is hardcode so there are some limitations: 49 | 50 | 1. Only work on python debugging with opencv module. 51 | 52 | 2. The python opencv module **must** support imwrite("filename to save", image_variable) function. 53 | 54 | 3. The python file **must** import opencv module as cv2 such as "import cv2" and import numpy as np such as "import numpy as np"; 55 | 56 | 4. The extension use imwrite to save the temporary image file. 57 | 58 | 5. The temporary directory is hardcode. 59 | 60 | 6. The temporary image file type is png. 61 | 62 | 7. The temporary image files are removed on extension activation not deactivation. 63 | 64 | 8. Unsupport variable tracking while debugging so the image cannot be refreshed automatically. You must click the variable again to refresh. 65 | 66 | ## Release Notes 67 | 68 | ### 0.0.11 69 | Fix an issue, use the globalStorageUri.fsPath instead of globalStorageUri.path. 70 | 71 | ### 0.0.10 72 | Due to a change in the Python debugger type name from 'python' to 'debugpy' after a Visual Studio Code update, this extension became incompatible. This update addresses the issue, ensuring compatibility with the latest VSCode version 1.86.1. Thanks to [aslampr07](https://github.com/aslampr07) (https://github.com/john-guo/simply-view-image-for-python-opencv-debugging/issues/24) 73 | 74 | ### 0.0.9 75 | 76 | Support TF2 tensor(Eager Execution must be enabled) or any other object that has a "numpy()" function which can convert it to a numpy array. Thanks to [saeedizadi](https://github.com/saeedizadi) (https://github.com/john-guo/simply-view-image-for-python-opencv-debugging/issues/13) 77 | 78 | ### 0.0.8 79 | 80 | Now the global variables can be view, but still cannot know which thread or stack frame current within so that if many variables with the same name in different threads or different stack frames the result will be confused. 81 | 82 | ### 0.0.7 83 | 84 | Using a workaround for supporting multithreading. Thanks to [zhfkt](https://github.com/zhfkt) (https://github.com/john-guo/simply-view-image-for-python-opencv-debugging/issues/6) 85 | 86 | ### 0.0.6 87 | 88 | Add an option "svifpod.usetmppathtosave" to choose which path (tmp or extenion private storage path) to save, default is tmp path. 89 | 90 | ### 0.0.5 91 | 92 | Add a command "View Image(Python OpenCV Debug)". 93 | 94 | Add a keyboard shortcut "ctrl+alt+Q" for quickly image viewing. 95 | 96 | ### 0.0.4 97 | 98 | Add ndarray checking to avoid some exceptions. 99 | 100 | ### 0.0.3 101 | 102 | Update README.md 103 | 104 | ### 0.0.2 105 | 106 | Add support for float np array. Notice it's a hardcode workaround. Because of this fixing the python file must import numpy as np also. Thanks to [marisancans](https://github.com/marisancans) (https://github.com/john-guo/simply-view-image-for-python-opencv-debugging/issues/1) 107 | 108 | ### 0.0.1 109 | 110 | Initial release 111 | 112 | **Enjoy!** 113 | --------------------------------------------------------------------------------