diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b943dbc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "deno.enable": true +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d05b402 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Zype Inc. + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6da417b --- /dev/null +++ b/README.md @@ -0,0 +1,83 @@ +# ShareImage +![Card](https://shimg.zype.cf/v1/image?title=Generate%20Social%20Share%20Images%20Dynamically!&cloudName=zype&imagePublicID=ShareImage/Docs-Card) +## Installation +There is currently 2 Langauges Supported: **Python** and **Node.js** +And there is a **API** available to use with your project! +### API (Beta, WIP) +The API is currently in beta and may have some issues. +The domain of the API is https://shimg.zype.cf/v1 +Currently, the V2 of ShareImage is only available for the Node.JS Library (with CommonJS, ESM and TypeScript support) +#### Endpoints +There is currently only one endpoint available: +##### GET `/image` +It needs Query Params in the following format: +https://shimg.zype.cf/v1/image?paramName=paramValue +The paramaters are as same as **Node.js** Params! +### Python +To Install ShareImage in Python with *PIP* Run: +```sh +pip install ShareImage +``` +### Node.js +To Install ShareImage in Node.js with *NPM* Run: +```sh +npm i shareimage --save +``` +Or, with *Yarn*: +```sh +yarn add shareimage +``` +## Usage +Using ShareImage is a bit different across Languages. +### Python +Use the Following Code to Generate a Image and print it's URL in Python: +```py +from ShareImage import ShareImage + +image = ShareImage( + title = "My Test Image", + cloudName = "myCloud", + imagePublicId = "myFolder/myImage" +) + +print(image) +``` +### Node.js +Use the Following Code to Generate a Image and output it's URL in Node.js (ES6): +```js +import * as ShareImage from 'shareimage'; + +const image = await ShareImage.generateImage( + "/path/to/image.png", + "My awesome title", + { type: "datauri" } +) + +console.log(image) +``` + +### Deno +You can use the [`sideno`](https://deno.land/x/sideno) library to use ShareImage in Deno! +Example: +```ts +import SI from "https://deno.land/x/sideno@VERSION/mod.ts"; +let img = new SI.Image("URL/Buffer of Image"); + +img.title.text = "Your desired title"; +img.tagline.text = "Your desired tagline"; + +let out = await img.export("buffer"); +await Deno.writeFile("out.png", out); +``` + +## Docs +Coming Soon... + +## Sponsors +We have been sponsored by **Vercel**, **MacStadium**. +Vercel gave us free **Pro Plan** access to host the documentation and other websites. +MacStadium gave us free **Mac Mini Server** to host the API and for builds. + +[![Powered By Vercel](https://res.cloudinary.com/zype/image/upload/ShareImage/powered-by-vercel.png)](https://vercel.com/?utm_source=zypeoss&utm_campaign=oss) + + diff --git a/deps.ts b/deps.ts new file mode 100644 index 0000000..1f5ce28 --- /dev/null +++ b/deps.ts @@ -0,0 +1 @@ +export {loadImage, createCanvas} from "https://deno.land/x/canvas@v1.4.1/mod.ts"; \ No newline at end of file diff --git a/mod.ts b/mod.ts new file mode 100644 index 0000000..d4aff76 --- /dev/null +++ b/mod.ts @@ -0,0 +1,88 @@ +import {loadImage, createCanvas} from "./deps.ts"; + +interface ImageTextFont { + src: ArrayBuffer, + alias: string, + family: string, +} + +interface ImageTextComponent { + text: string, + posX: number, + posY: number, + font: Promise | ImageTextFont, + color: string +} + +class Font { + src: string | ArrayBuffer; + alias: string; + family: string; + constructor (src: string | ArrayBuffer, alias: string, family: string) { + this.src = src; + this.alias = alias; + this.family = family; + } + async export() { + let buf: ArrayBuffer; + if (typeof this.src === "string") { + buf = await (await fetch(this.src)).arrayBuffer(); + } else { + buf = this.src; + } + return { + src: buf, + alias: this.alias, + family: this.family + } + + } +} + +/** A class of the SI.Image */ + +export class Image { + TITLE_FONT_SIZE = 64; + TAGLINE_FONT_SIZE = 48; + TAGLINE_Y = 320; + IMAGE_WIDTH = 1280; + IMAGE_HEIGHT = 669; + src: string|Uint8Array; + title: ImageTextComponent = {text: "", posX: 480, posY: 254, font: (new Font("https://github.com/Zype-Z/ShareImage.js/raw/main/assets/fonts/sirin-stencil.ttf", "sirin", "Sirin Stencil")).export(), color: "black"}; + tagline: ImageTextComponent = {text: "", posX: 480, posY: 320, font: (new Font("https://github.com/Zype-Z/ShareImage.js/raw/main/assets/fonts/arial.ttf", "arial", "Arial")).export(), color: "black"}; + constructor (src: string |Uint8Array){ + this.src = src; + } + /** + * @param {"buffer" | "data"} _type - Buffer or Data URI export option. + * @returns {Promise} A Promise containing the ArrayBuffer or Data URI of the output image. + */ + export(_type: "buffer" | "data") { + return (async () => { + const img = await loadImage(this.src); + const canvas = createCanvas(this.IMAGE_WIDTH, this.IMAGE_HEIGHT); + const ctx = canvas.getContext("2d"); + const title_font = await this.title.font; + const tagline_font = await this.tagline.font; + await canvas.loadFont(title_font.src, {family: title_font.alias}); + await canvas.loadFont(tagline_font.src, {family: tagline_font.alias}); + ctx.drawImage(img, 0, 0); + ctx.font = `${this.TITLE_FONT_SIZE}px ${title_font.alias}`; + ctx.fillText(this.title.text, this.title.posX, this.title.posY); + if (this.tagline.text) { + ctx.font = `${this.TAGLINE_FONT_SIZE}px ${tagline_font.alias}`; + ctx.fillText(this.tagline.text, this.tagline.posX, this.tagline.posY); + } + if (_type === "buffer") { + return canvas.toBuffer("image/png"); + } else { + return canvas.toDataURL("image/png", 100); + } + })() + } +} + +export default { + Font, + Image +} \ No newline at end of file