{"id":13682573,"url":"https://github.com/devforth/painterro","last_synced_at":"2025-05-15T09:04:31.049Z","repository":{"id":38325015,"uuid":"94651637","full_name":"devforth/painterro","owner":"devforth","description":"Painterro - JavaScript painting plugin","archived":false,"fork":false,"pushed_at":"2024-09-18T14:38:33.000Z","size":23232,"stargazers_count":650,"open_issues_count":23,"forks_count":88,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-04-14T22:16:14.093Z","etag":null,"topics":["crop","frontend","javascript","paint","painter","painting","plugin","raster-graphics","screenshot","wysiwyg"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devforth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":null,"patreon":"devforth","open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2017-06-17T22:07:02.000Z","updated_at":"2025-03-30T09:45:19.000Z","dependencies_parsed_at":"2024-04-09T15:57:45.936Z","dependency_job_id":"ed623a72-17db-4890-9944-18855d47b216","html_url":"https://github.com/devforth/painterro","commit_stats":{"total_commits":621,"total_committers":30,"mean_commits":20.7,"dds":0.4122383252818036,"last_synced_commit":"82a3f3dbf08ccd99d0951ef33a7040872498598c"},"previous_names":[],"tags_count":175,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devforth%2Fpainterro","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devforth%2Fpainterro/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devforth%2Fpainterro/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devforth%2Fpainterro/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devforth","download_url":"https://codeload.github.com/devforth/painterro/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248968918,"owners_count":21191162,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crop","frontend","javascript","paint","painter","painting","plugin","raster-graphics","screenshot","wysiwyg"],"created_at":"2024-08-02T13:01:48.783Z","updated_at":"2025-04-14T22:16:33.728Z","avatar_url":"https://github.com/devforth.png","language":"JavaScript","funding_links":["https://patreon.com/devforth","https://www.patreon.com/devforth"],"categories":["JavaScript"],"sub_categories":[],"readme":"\u003cimg src=\"https://raw.githubusercontent.com/devforth/painterro/master/res/painterro.png\" align=\"right\" style=\"padding:5px; width:70px\" /\u003e \n\n**[live demo](https://tracklify.com/painterro_demo/)** | [npm](https://www.npmjs.com/package/painterro) | [GitHub](https://github.com/devforth/painterro)\n\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;  ![npmvers](https://img.shields.io/npm/v/painterro) ![npmDown](https://img.shields.io/npm/dw/painterro?label=npm%20💾) ![totalNpm](https://img.shields.io/npm/dt/painterro?label=npm%20💾) ![ghdownloads](https://img.shields.io/github/downloads/devforth/painterro/total?label=github%20script%20💾) \n\nJavaScript painting plugin which allows editing images in a browser.\nCan be easily integrated into any website or webapp by calling simple initialization code.\n\n🆕 Check out our simple and game-changing opensource [Vue admin framework](https://adminforth.dev/) with a great look and extensibility!\n\n\n\u003e 🙏🙏🙏 Scream for help to Ukraine \n\u003e \n\u003e 24 February 2022, Russia started bombing cities with peacefully civilized population in whole Ukraine. And has been doing it up to this day. Breaking all laws of war. Their bombs has been killing children and adults. This deserves Hague court.\n\u003e - 🏠 If you are from Russia, please stop your government by any means including protests, don't trust local media, they are bribed by the government. They always was. I am sure you already feel lie by unexplainable crazy things in your country caused by world sanctions.\n\u003e - 💣 Please spread the information about bombing of Ukraine in all social way you could. Russia treacherously broke into the territory of a sovereign state. Do not trust to anything from Russian media, most likely it will be bullshit\n\u003e - 💼 If you have any kind of business cooperation with Russia, please block it now and keep most of money on your side, this is the only possible ethical decision\n\u003e - ☢️ Ask your government to stop Russia from spreading invasion in any way. Russia is nuclear threat to the whole world. You think it is not possible? We thought that bombing of independent country with population of 44.13 million is also not possible.\n\n\nFeatures\n========\n\n- Paste image from clipboard with `Ctrl+V` (e.g. `PtnScr` screenshot), drag and drop it into widget, or load with file select dialog\n- Crop image by defined area\n- Paint primitives: line, rectangle, ellipse (alpha color can be used)\n- Brush – free drawing tool e.g. to implement finger-based signatures on tablet screens\n- Add text (you can use `Ctrl+B` - bold, `Ctrl+I` - italic, `Ctrl+U` - underlined, or just pase formatted HTML)\n- Rotate / resize, scale image\n- Pixelize some area to hide sensitive data\n- Draw arrows\n- Trash can tool to clear the canvas\n- Paint bucket tool for color fills\n- Add filters to images\n\n\u003cimg alt=\"Painterro gif preview\" src=\"https://raw.githubusercontent.com/devforth/painterro/master/docs/painterro_gif.gif\" \n style=\"box-shadow: 0 0 20px lightgrey; margin: 0 0 20px 0;\" /\u003e \n\nUsed by\n=================\n\n  \u003ctable border=\"0\"\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cbr\u003e\n      \u003ca href=\"https://nasa.github.io/openmct/\"\u003e\u003cimg src=\"https://nasa.github.io/openmct/static/res/images/logo-nasa.svg\" height='100px'/\u003e\u003c/a\u003e\n      \u003cbr\u003e\n      \u003ca href=\"https://nasa.github.io/openmct/\"\u003eNASA Open MCT\u003c/a\u003e\n      \u003cbr\u003e\n      \u003cbr\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\n      \u003cbr\u003e\n      \u003ca href=\"https://github.com/CiscoDevNet\"\u003e\u003cimg src=\"https://upload.wikimedia.org/wikipedia/commons/6/64/Cisco_logo.svg\" height='100px'/\u003e\u003c/a\u003e\n      \u003cbr\u003e\n      \u003ca href=\"https://github.com/CiscoDevNet\"\u003eCisco DevNet\u003c/a\u003e\n      \u003cbr\u003e\n      \u003cbr\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e \n      \u003cbr\u003e\n      \u003ca href=\"https://tracklify.com\" \u003e\u003cimg src=\"https://tracklify.com/static/img/header-logo.4916e646b063.svg\" height='100px' /\u003e\u003c/a\u003e\n      \u003cbr\u003e\n      \u003ca href=\"https://tracklify.com\"\u003eTracklify\u003c/a\u003e\n      \u003cbr\u003e\n      \u003cbr\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\"\u003e \n      \u003cbr\u003e\n      \u003ca href=\"https://fastdivs.com\" \u003e\u003cimg src=\"https://fastdivs.com/static/svg/logo.c1c15aa6d612.svg\" height='100px' /\u003e\u003c/a\u003e\n      \u003cbr\u003e\n      \u003ca href=\"https://fastdivs.com\"\u003eFastDivs\u003c/a\u003e\n      \u003cbr\u003e\n      \u003cbr\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003c/table\u003e\n  \u003cbr\u003e\n\n\nAdvantages 💪\n=============\n\n- It is lightweight and minimalistic - written with vanilla JS, you don't need dependencies to use it\n- Designed to process images with minimal clicks, most actions support hot-keys\n- Could be easily integrated into SPA application (React, Vue, Angular)\n- Could be used in Electron and Cordova apps\n- Flexibale image saving - you provide your save handler, and get base64 data with any jpeg/png compression\n- Could be translated to any language \n\nOriginally Painterro was designed for quick screenshots processing: You make screenshot by pressing `PrtSc` button,\nthen open Painterro on your website, paste an image with `Ctrl+V`,\ncrop it to interested area, highlight something with line/rectangle tool and/or add some text \nto the image and save on server with custom save handler (e.g. simple `XHR` request to your backend).\nIn addition, you can use Painterro as image editor for any kind of raster images. Please try a [demo](https://tracklify.com/painterro_demo/).\nAlso painterro has [Wordpress Plugin](https://wordpress.org/plugins/painterro/).\n\nIf you want to see some feature in Painterro, please leave (or vote for) an issue [here](https://github.com/devforth/painterro/issues).\nThere is no promise that it will be implemented soon or ever, but it is interesting to know what features users want to have.\n\nUsefull hints and tweaks 😋:\n\n- [Painterro JS paint features review on HINTY](https://hinty.io/devforth/js-paint-plugin-for-your-website/)\n- [Dark theme for Painterro JS paint](https://hinty.io/devforth/painterro-dark-theme/)\n- [Round buttons for Painterro JS paint](https://hinty.io/devforth/how-to-round-the-painterro-buttons/)\n\n\nTable of contents\n=================\n\n  * [Table of contents](#table-of-contents)\n  * [Installation](#installation)\n    * [With npm](#with-npm)\n    * [By including script](#by-including-script)\n    * [Read after installation](#read-after-installation)\n  * [Supported hotkeys](#supported-hotkeys-)\n  * [Configuration](#configuration-)\n    * [Events](#events)\n    * [UI color scheme](#ui-color-scheme)\n    * [API](#api)\n    * [Translation](#translation-)\n  * [Saving image](#saving-image-)\n    * [Base64 saving](#base64-saving)\n    * [Binary saving](#binary-saving)\n    * [Saving to WYSIWYG](#saving-to-wysiwyg)\n    * [Format and quality](#format-and-quality)\n    * [Example: Open Painterro by Ctrl+V](#example-open-painterro-by-ctrlv)\n  * [Development](#development-)\n    * [Building painterro](#building-painterro)\n    * [Dev-server](#dev-server)\n    * [Regenerating icons font](#regenerating-icons-font)\n\n\nInstallation\n============\n\n\nWith npm\n--------\n\nIf you have npm-based project (e.g. SPA like React/Vue) you can run:\n```bash\nnpm install painterro --save\n```\nThen in your code\n\n```js\nimport Painterro from 'painterro'\n...\nPainterro().show()\n```\n\nBy including script\n-------------------\n\nYou can download latest `painterro-*.min.js` here https://github.com/devforth/painterro/releases/ \nor [build it by yourself](#building-painterro).\n\nThen insert `\u003cscript\u003e` e.g to `\u003chead\u003e` section of your HTML file:\n```html\n\u003cscript src=\"/xxx/painterro-x.x.x.min.js\"\u003e\u003c/script\u003e\n```\nThen in your code (`body` section, `onclick` handler, etc):\n```html\n\u003cscript\u003e\n  Painterro().show()\n\u003c/script\u003e\n```\nSee [jsfiddle.net example](https://jsfiddle.net/vanbrosh/wnebj4h7/)\n\n\nRead after installation\n-----------------------\n\nTo be able to save edited images on server or client see [Saving image](#saving-image). For configurations see [Configuration](#configuration)\n\nSupported hotkeys ⌨\n=================\n\n| | |\n|-|-|\n| `Ctrl + Z` | Cancel last operation |\n| `Ctrl + V` | Paste image from clipboard |\n| `Ctrl + C` | Copy selected aria to clipboard |\n| `Shift` when drawing **rect**/**ellipse** | Draw **square**/**circle** |\n| `Shift` when drawing **line** | draw at angles of `0`, `45`, `90`, `135` etc degrees | \n| `Alt` when using pipette | Hide zoom helper (colored grid) |\n| `Ctrl` + `Wheel mouse up/down` | Zoom image |\n| `Ctrl + S` | Save image |\n\nAlso some tools have own one-button hotkeys e.g. `C` - crop, you could see this shortcuts if you will hold mouse on toolbutton.\n\nConfiguration ⚙\n=============\n\nYou can pass parameters map to Painterro constructor:\n```js\nPainterro({\n  activeColor: '#00ff00', // default brush color is green\n  // ... other params here\n})\n```\n\n| Param | Description | Default |\n|-|-|-|\n| `id` | If provided, then Painterro will be placed to some holder on page with this `id`, in other case holder-element will be created (fullscreen with margins). Important note: If you are using your block and id option, please add `position`:`relative` or `absolute` or `fixed` on your container, default (`static`) will lead to positioning issues | `undefined` |\n|`activeColor`| Line/Text color that selected by default | `'#ff0000'` |\n|`activeColorAlpha` | Transparancy of `activeColor` from `0.0` to `1.0`, `0.0` = transparent | `1` |\n|`activeFillColor` | Fill color that selected by default | `'#000000'` |\n|`activeFillColorAlpha` | Transparancy of `activeColor` from `0.0` to `1.0` | `0` |\n|`defaultLineWidth` | Line width in `px` that selected by default | `5` |\n|`defaultPrimitiveShadowOn` | Enable Shadow for primitive tools (easier recognize them on a screenshots) | `true` |\n|`defaultEraserWidth` | Eraser width in `px` that selected by default | `5` |\n|`backgroundFillColor` | Default background color when image created/erased | `'#ffffff'` |\n|`backgroundFillColorAlpha`| Transparancy of `backgroundFillColor` from `0.0` to `1.0` | `1.0` |\n|`textStrokeColor`| Stroke color of text tool | `'#ffffff'` |\n|`textStrokeColorAlpha`| Stroke color of text tool | `1.0` |\n|`shadowScale`| Change text shadow blur for text and arrow | `1.0` |\n|`defaultFontSize` | Default font size in pixels | `24` |\n|`backplateImgUrl`| background for drawing, doesn't include in final image |`undefined` |\n|`defaultTextStrokeAndShadow` | Enables Stroke and Shadow for text tool by default (easier recognize text on screenshots) | `true` |\n|`defaultSize` | default image size, should be string in format `\u003cwidth\u003ex\u003cheight\u003e` in pixel, e.g. `'200x100'`. If value is `'fill'`(default) than all container size will be used | `'fill'` |\n|`defaultTool` | Tool selected by default | `'select'` | \n|`hiddenTools` | List of tools that you wish to exclude from toolbar. Subset from this list `['crop', 'line', 'arrow', 'rect', 'ellipse', 'brush', 'text', 'rotate', 'resize',  'save', 'open', 'close', 'undo', 'redo', 'zoomin', 'zoomout', 'bucket']`, You can't hide default tool | `['redo']` |\n|`initText` | Display some centered text before painting (supports HTML). If null, no text will be shown | `null` |\n|`initTextColor` | Color of init text | `'#808080'` |\n|`initTextStyle` | Style of init text | `\"26px 'Open Sans', sans-serif\"` |\n|`pixelizePixelSize` | Default pixel size of pixelize tool. Can accept values - `x` - x pixels, `x%` - means percents of minimal area rectangle side | `20%` |\n|`pixelizeHideUserInput` | Don't allow users to enter pixel size In settings tools (and save in localstorage), this would allow developer to freeze pixel size by using params `pixelizePixelSize` to make sure users will not set low pixel sizes | `false` |\n|`availableLineWidths` | A list of the line width values that are available for selection in a drop down list e.g. `[1,2,4,8,16,64]`.  Otherwise an input field is used. | `undefined` |\n|`availableArrowLengths` | A list of the arrow sizes values that are available for selection in a drop down list e.g. `[10,20,30,40,50,60]`.  Otherwise an input field is used. | `undefined` |\n| `defaultArrowLength` | default arrow length | `15` |\n|`availableEraserWidths` | A list of the eraser width values that are available for selection in a drop down list e.g. `[1,2,4,8,16,64]`.  Otherwise an input field is used. | `undefined` |\n|`availableFontSizes` | A list of the font size values that are available for selection in a drop down list e.g. `[1,2,4,8,16,64]`.  Otherwise an input field is used. | `undefined` |\n|`toolbarPosition` | Whether to position the toolbar at the top or bottom. | `'bottom'` |\n|`fixMobilePageReloader` | By default painterro adds overflow-y: hidden to page body on mobile devices to prevent \"super smart\" feature lice Chrom's reload page. Unfortunately we can't prevent it by preventDefault. If your want to scroll page when painterro is open, set this to false | `true` |\n|`language` | Language of the widget. | `'en'` |\n|`how_to_paste_actions`| List of paste options that will be suggested on paste using some paste dialog e.g. `['extend_right', 'extend_down'] `. If there is only one option in list, then it will chosen automatically without dialog | `['replace_all', 'paste_over', 'extend_right', 'extend_down']` |\n|`replaceAllOnEmptyBackground`| Whether to select `replace_all` without dialog on first paste after painterro was just opened. So it will replaces background with image (will change dimensions to pasted image when background is empty) | `true` |\n|`hideByEsc`| If `true` then `ESC` press will hide widget | `false` | \n|`saveByEnter`| If `true` then `ENTER` press will do same as `Ctrl+S` | `false` | \n|`extraFonts`| By default Text tool supports only several [predefined](https://github.com/devforth/painterro/blob/master/js/text.js#L38) fonts due to compatibility considirations , but yousing this option you can add any fonts you want if you are sure they are available on your page/app | `['Roboto']` |\n|`toolbarHeightPx`| Height of toolbar in pixels | `40` | \n|`buttonSizePx`| Button for toolbar in pixels | `32` |\n|`bucketSensivity`| Bucket tool sensivity | `100` |\n|`customTools`| List of the custom tools which will appear at the left menu after default options. Custom tool includes three options : | `{name:string, callBack:function, iconUrl:dataURL string or URL}` |\n\n## Events\n\n| Param | Description | Accepted Arguments |\n|-|-|-|\n| `onBeforeClose` | Function that will be called when user closes painterro it, call `doClose` to confirm close | `hasUnsavedChaged: bool`, `doCloseCallback: function` |\n| `onClose` | If passed will be triggered when painterro closed by X button (use `onHide` for all close reasons) | `undefined` |\n| `onHide` | If passed will be triggered when painterro hides (by X button or save or any other way) | `undefined` |\n| `onChange` | Function that will be called if something will be changed (painted, erased, resized, etc) | `\u003cexportable image\u003e` | `undefined` |\n| `onUndo` | Function that will be called if user will undo (`Ctrl+Z`) | `{\u003ccurrent history state\u003e}` |\n| `onRedo` | Function that will be called if user will redo (`Ctrl+Z`) | `{\u003ccurrent history state\u003e}` |\n|`onImageFailedOpen`| Function that will be called if image can`t open | `undefined` |\n| `onImageLoaded` | Function that will be called if you passed image to `show` and when it was loaded | `undefined` | \n| `saveHandler` | Function that will be called when user presses Save (or `Ctrl+S`), Call `doneCallback` to reflect in painterro that image was saved | `{\u003cexportable image\u003e}`, `doneCallback : function` |\n\n\nEvents accepted arguments:\n\n* `{\u003cexportable image\u003e}` is object:\n\n```\n{ \n  image: {\n   asBlob: ƒ asBlob(type, quality) // returns blob\n   asDataURL: ƒ asDataURL(type, quality) // returns e.g. \"data:image/jpeg;base64,/9j/4AAQS....\"\n   suggestedFileName: ƒ suggestedFileName(type) // returns string\n   hasAlphaChannel(): ƒ suggestedFileName() // returns true or false\n   getOriginalMimeType: ƒ getOriginalMimeType() // e.g. image/jpeg;\n   getWidth: ƒ getWidth() // integer\n   getHeight: ƒ getHeight() // integer\n  }\n  operationsDone: int // integer\n} \n```\n\n* `{\u003ccurrent history state\u003e}` is object:\n\n```\n{\n  prev: {\u003ccurrent history state\u003e} or undefined\n  next: {\u003ccurrent history state\u003e} or undefined\n  prevCount: int\n  sizeh: int\n  sizew: int\n}\n```\n\n\n\n\nUI color scheme\n---------------\n\nNext group of params used to configure painterro user interface in simple \"JS way\". \nThey should be placed under `colorScheme` group, for example:\n```js\nPainterro({\n  colorScheme: {\n    main: '#fdf6b8', // make panels light-yellow\n    control: '#FECF67' // change controls color\n  }\n}).show()\n```\n\n| Param | Description | Default |\n|-|-|-|\n|`main` | Color of panels, take most of UI space | `'#fff'` |\n|`control` | Color of controls background (e.g. button background) | `'#fff'` |\n|`controlShadow` | Color controls box shadow | `'0px 0px 3px 1px #bbb'` |\n|`controlContent` | Content of controls (e.g. button text) | `'#000000'` |\n|`activeControl` | Color for control when it active (e.g. button pressed) | `'#7485B1'` |\n|`activeControlContent` | Color for activated control content | `main` |\n|`inputBorderColor` | You can add border to inputs, by default color is same as `main` so borders will not be seen | `main` |\n|`inputBackground` | Background of inputs | `'#ffffff'` |\n|`inputShadow` | shadow of input | `'inset 0 0 4px 1px #ccc'` |\n|`inputText` | Color of text in input | `activeControl` |\n|`backgroundColor`| Background color of component area which left outside of image due to it size/ratio | `'#999999'` |\n|`dragOverBarColor`| Color of bar when dropping file to painterro | `'#899dff'` |\n|`hoverControl`| Controls color when mouse hovered | `control` |\n|`hoverControlContent`| Controls background color when mouse hovered | `'#1a3d67'` |\n|`toolControlNameColor`| Color of toolbar labels that prepend controls | `rgba(255,255,255,0.7)` |\n\n\u003e NOTE: all these params are defined only for simplicity, you are free to redefine them in your cascade style files (we don't use importants and so on, so all props should be easily editable). This mettod is recommended for experts - because you can use your CSS preprocessor variables and adopt Painterro for your design. Example usecase is different color of shadows for a buttons with `::after`/`::before`\n\nAPI\n-------\n\n**.show([optional]openImage, [optional]initialMimeType)** - Shows painterro instance. `openImage` can have next values:\n\n* `false` - will open image that already was drawn before last close\n* `some string value`, e.g. `'http://placehold.it/120x120\u0026text=image1'` - will try to load image from url\n* all another values - will clear content before open\n\n`initialMimeType` could be used to help painterro understand which file do you try to load there. Could be useful if you want to save the original mime and file opened explicitly (painterro open tool or dnd/ctrl+v handlers get it automatically)\n\n**.hide()** - hide instance\n\n**.setColor(options)** - sets the color of the chosen tool , or changes initial value of color. `options` should be array with two values, `[target,colorWidgetState]`\n\navailable values for `target`:\n\n|`line`|, |`bg`| \n\n`colorWidgetState` - object with requred properties :\n\n* `palleteColor` - color string . Just indicates which color will be shown on the collor pallete.\n* `alpha` - number in range from 0 to 1. The same but for alpha channel. \n* `alphaColor` - color string. Color with alpha, which will be using for drawing element.\n\n\u003eNOTE: `paleteColor` and `alpha` is using only for displaing right values in color picker widget, this two options don't effect on color which will be used for drawing elements.\n\n**.setLineWidth()** - set line width for chosen tool. \n\n**.setArrowLength()** - set width for chosen arrow.\n\n**.setEraserWidth()** - set width of eraser\n\n**.setShadowOn()** - set shadowfor line elements or arrow element. It takes boolean value. \n\n**.save()** - call save (same save as on buttons bar). Can be used if save button is hidden (`hiddenTools: ['save']`)\n\n**.doScale({ width, height, scale })** - scale the image and resize area.\n\nScale to match the width and scale height proportinally (e.g. 50x32 will become 100-\u003e64):\n\n```\n.doScale({width: 100})\n```\n\nScale to fill width and height (e.g. 50x32 will become 11-\u003e15):\n\n```\n.doScale({width: 11, height: 15})\n```\n\nScale x2  (e.g. 11x12 will become 22-\u003e24):\n\n```\n.doScale({ scale: 2 })\n```\n\n\n\nExample:\n\n```js\nvar p = Painterro()\np.show()\n```\n\nTranslation 📙\n--------------\n\nWant to translate Painterro into your language?\n\nIf you need one of languages in table below, just pass pass `language` parameter, for example:\n \n```js\nPainterro({\n  language: 'es'  // Spanish\n}).show()\n```\nTranslated languages:\n\n| `language` param | Name |\n|-|-|\n| `ca` | Catalan |\n| `de` | German |\n| `en` | English |\n| `es` | Spanish |\n| `fa` | Iran-Farsi (Persian (Ir-Fa) |\n| `fr` | French |\n| `ja` | Japanese |\n| `pl` | Polish |\n| `pt-PT` | European Portuguese |\n| `pt-BR` | Brazilian  Portuguese |\n| `ru` | Russian |\n| `nl` | Dutch |\n\n\n\nIf you want to add another language, then:\n\n1. fork to your GitHub with button on top.\n2. Create empty file in folder langs [\u003cLANG_ISO_CODE\u003e.lang.js] for your translation. `LANG_ISO_CODE` should follow [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)\n3. Copy content from [langs/en.lang.js] to a new file\n4. Then translate all `'Strings'`\n5. Add reference in [js/translation.js] inside of your repo. \n5. After that create pull-request, or just open [issue](https://github.com/devforth/painterro/issues) if you don't know how to create a PR.\n\n🤔 Found a bug in some word for your language? Feel free to edit on GitHub directly and suggest a fix.\n \nIf you want to translate or change strings without contributing you can do this by passing \n`translation` parameter, for example:\n\n```js\nPainterro({\n  translation: {\n    name: 'ua',\n    strings: {\n      apply: 'Застосувати'    \n      // other strings\n    }\n  }\n}).show()\n```\nFor all strings that should be translated, see [langs/en.lang.js] \n    \n\nSaving image 💾\n===============\n\nYou should provide your own save handler, that will post/update image on server or will pass image to other\nfrontend components. In this section we will provide several backend examples on python Flask (easiest web server for python). Anyway if you will face any python exception you can use super-helpfull [fixexception.com](https://fixexception.com/) service to fix any issue you will face 💪.\n\nBinary saving\n-------------\n\nYou can post data with binary `multipart/form-data` request which is the most efficient way to pass data to backend. Example uses raw `XMLHttpRequest`. Of course,\n you can use `fetch`, `jQuery`, etc insead.\n\n```js\nvar ptro = Painterro({\n  saveHandler: function (image, done) {\n    var formData = new FormData();\n    formData.append('image', image.asBlob());\n    // you can also pass suggested filename \n    // formData.append('image', image.asBlob(), image.suggestedFileName());\n    var xhr = new XMLHttpRequest();\n    xhr.open('POST', 'http://127.0.0.1:5000/save-as-binary/', true);\n    xhr.onload = xhr.onerror = function () {\n      // after saving is done, call done callback\n      done(true); //done(true) will hide painterro, done(false) will leave opened\n    };\n    xhr.send(formData);\n  }\n})\nptro.show();\n```\nHere is python flask backend example (of course same can be implemented using any technology):\n```python\n@app.route(\"/save-as-binary/\", methods=['POST'])\ndef binary_saver():\n    filename = '{:10d}.png'.format(int(time()))  # generate some filename\n    filepath = os.path.join(get_tmp_dir(), filename)\n    request.files['image'].save(filepath)\n    return jsonify({})\n```\n\nSee full example in `example` directory. You can run it used python3 with installed `Flask` (`pip install flask`).\n\nBase64 saving\n-------------\n\n\nYou can also same image by posting `base64` string via plain POST json call.\nPlease note that base64 encoding is less efficient then binary data, for example some `1920 x 1080` image took `402398` bytes for `base64` upload.\nThe same image took `301949` bytes with `multipart/form-data`.\n\n\n```js\nvar ptro = Painterro({\n    saveHandler: function (image, done) {\n      // of course, instead of raw XHR you can use fetch, jQuery, etc\n      var xhr = new XMLHttpRequest();\n      xhr.open(\"POST\", \"http://127.0.0.1:5000/save-as-base64/\");\n      xhr.setRequestHeader(\"Content-Type\", \"application/json\");\n      xhr.send(JSON.stringify({\n        image: image.asDataURL()\n      }));\n      xhr.onload = function (e) {\n        // after saving is done, call done callback\n        done(true); //done(true) will hide painterro, done(false) will leave opened\n      }\n    },\n    activeColor: '#00b400'  // change active color to green\n});\nptro.show();\n```\nBackend should convert `base64` to binary and save file:\n```python\n@app.route(\"/save-as-base64/\", methods=['POST'])\ndef base64_saver():\n    filename = '{:10d}.png'.format(int(time()))  # generate some filename\n    filepath = os.path.join(get_tmp_dir(), filename)\n    with open(filepath, \"wb\") as fh:\n        base64_data = request.json['image'].replace('data:image/png;base64,', '')\n        fh.write(base64.b64decode(base64_data))\n    return jsonify({})\n```\n\n\nSaving to WYSIWYG\n-----------------\n\nYou can just insert image as data url to any WYSIWYG editor, e.g. TinyMCE:\n```js\n    tinymce.init({ selector:'textarea', });\n    var ptro = Painterro({\n      saveHandler: function (image, done) {\n        tinymce.activeEditor.execCommand('mceInsertContent', false, '\u003cimg src=\"' + image.asDataURL() + '\" /\u003e');\n        // after saving is done, call done callback\n        done(true); //done(true) will hide painterro, done(false) will leave opened\n      }\n    })\n```\n\nFormat and quality\n------------------\n\nWhen you call `image.asDataURL()` or `image.asBlob()`, you can also specify image mime type (format), e.g.\n`image.asDataURL('image/jpeg')`. \n\nDefault type is mimetype used by image which was loaded into Painterro, or \"image/png\" if image was created from scratch.\n\nIf type is `image/jpeg` or `image/webp`, you can also define image quality from `0.0` to `1.0`, default is `0.92`,\nexample: `image.asDataURL('image/jpeg', 0.5)`\n\n\nSave to jpeg or png depending on whether there is an alpha channel\n------------------\n\nAn efficient way to save an image might be implmented by checking whether image has some alpha pixels:\n* If yes - we need to serve image in less efficient png format\n* Otherwise lets just use JPEG\nThis is very simple with next:\n\n```\nvar ptro = Painterro({\n  saveHandler: function (image, done) {\n\n    image.asBlob(image.hasAlphaChannel() ? 'image/png' : 'image/jpeg');\n    // upload blob\n  }\n})\n```\n\nExample: Open Painterro by Ctrl+V\n-----------------\n\n```js\ndocument.onpaste = (event) =\u003e {\n  const { items } = event.clipboardData || event.originalEvent.clipboardData;\n  Array.from(items).forEach((item) =\u003e {\n    if (item.kind === 'file') {\n      if (!window.painterroOpenedInstance) {\n        // if painterro already opened - it will handle onpaste\n        const blob = item.getAsFile();\n        const reader = new FileReader();\n        reader.onload = (readerEvent) =\u003e {\n            window.painterroOpenedInstance = Painterro({\n              onHide: () =\u003e {\n                window.painterroOpenedInstance = undefined;\n              },\n              saveHandler: (image, done) =\u003e {\n                console.log('Save it here', image.asDataURL());  // you could provide your save handler\n                done(true);\n              },\n            }).show(readerEvent.target.result, item.type);\n        };\n        reader.readAsDataURL(blob);\n      }\n    }\n  });\n};\n```\n\nIf you face any painterro errors (exceptions), please reffer to [Painterro page on FixJSError](https://fixjserror.com/package/painterro/)\n\nDevelopment 🔨\n==============\n\nLatest supported NodeJS version is 16, use nvm to switch to it:\n\n```\nnvm install 16\nnvm use 16\n```\n\nCode written on ES6 which transplited by Babel and packed (minified) to a single file using webpack. All configs are inside so all you have to do after pulling repo is installing node modules:\n\n```bash\ncd painterro\nnpm ci\n```\n\nBuilding painterro\n------------------\n\n```bash\nnpm run build\n```\n\nResult file for `\u003cscript\u003e` import is `build/painterro.min.js`.\n\nActually, above command produces 4 versions of library:\n\n- `build/painterro-x.y.z.min.js`, `build/painterro.min.js` the same files but with different filenames (with and without versiontag) - this is `var` version which will be loaded as global variable (`var painterro = \u003cLibrary class\u003e`) when you will import it as `\u003cscript src='painterro.min.js' /\u003e` tag. So this is for `script` tag only.   \n- `build/painterro.commonjs2.js` - this version sutable for js `require/import`. That's why it is used as entry point in `package.json` file - if you are using webpack or other tool that can handle `require/import` of `commonjs2` libraries then you can do `npm install painterro`, and do `import painterro` and it will use `commonjs2` version.\n- `build/painterro.amd.js` and `build/painterro.umd.js` - these both are same as above but for `AMD` and `UMD` importers respectivly.\n\n\nDev-server\n----------\n\nTo start hot-reload dev server (for reloading code \"on the fly\"):\n```bash\nnpm run dev\n```\nThen open http://localhost:3000 with demo page\n\n\nEditing source on the fly for painterro imported from side webpack app (e.g. your project SPA)\n------------------------------------------\n\n1. If your side app uses 'eslint' it, most likely side app will need eslint-plugin-import:\n\n```\nnpm i eslint-plugin-import\n```\n\n2. Since compiled painterro commonjs2 file already linted and minimized you need to exclude it from linting:\n\nAdd to package.json of your side app:\n```\n  \"eslintIgnore\": [\n    \"/home/ivan/devforth/painterro/build/painterro2.commonjs.js\"\n  ],\n```\nwhere `/home/ivan/devforth/painterro` is a folder with Painterro sources\n\n3. Replace\n\n```\nimport Painterro from 'painterro';\n```\nwith\n \n```\nimport Painterro from '/home/ivan/devforth/painterro/build/painterro.commonjs2.js';\n```\n\n4. Go to painterro source folder and run:\n\n```\nwatch npm run build\n```\n\nRegenerating icons font\n-----------------------\n\nIf you need add/edit icons in `res` folder, please after editing run:\n\n```bash\nnpm run buildfont\n```\n\nFor font generation we use method described here: [How to generate a webfont (automated setup)](https://hinty.io/brucehardywald/how-to-generate-a-webfont-automated-setup/)\n\n\n\nContributing \n------------\n\nPull-requests are welcome.\n\nIf you want to say thank us [Patreon is here](https://www.patreon.com/devforth)\n\n\n[npm]: https://img.shields.io/npm/v/painterro.svg\n[npm-url]: https://npmjs.com/package/painterro\n\n[deps]: https://david-dm.org/webpack/painterro.svg\n[deps-url]: https://david-dm.org/webpack/painterro\n\nSupported by [DevForth](https://devforth.io) - Best quality, rapid,  modern tech development services\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevforth%2Fpainterro","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevforth%2Fpainterro","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevforth%2Fpainterro/lists"}