Repository: makkoncept/colorpalette
Branch: master
Commit: 0defd21205c0
Files: 19
Total size: 21.4 KB
Directory structure:
gitextract_53ta_i2o/
├── .gitignore
├── LICENSE
├── Procfile
├── README.md
├── app.json
├── colorpalette/
│ ├── __init__.py
│ ├── color.py
│ ├── forms.py
│ ├── routes.py
│ ├── static/
│ │ ├── css/
│ │ │ └── style.css
│ │ ├── images/
│ │ │ └── favicon/
│ │ │ └── site.webmanifest
│ │ └── js/
│ │ └── script.js
│ └── templates/
│ ├── 413.html
│ ├── base.html
│ ├── index.html
│ └── picture.html
├── config.py
├── requirements.txt
└── run.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
venv/
venv
__pycache__/
colorpalette/__pycache__
.idea
*.pyc
.vscode/
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2018 Mayank Nader
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.
================================================
FILE: Procfile
================================================
web: gunicorn colorpalette:app
================================================
FILE: README.md
================================================
<p align="center">
<img height=200 src="https://github.com/makkoncept/colorpalette/blob/master/.readme_assets/color-palette.png?raw=true"><br>
<h1 align="center">ColorPalette</h2>
<p align="center">A simple web app to extract dominant colors from an image.<p>
<p align="center">
<a href="https://github.com/makkoncept/colorpalette/blob/master/LICENSE">
<img alt="MIT License" src="https://img.shields.io/github/license/makkoncept/colorpalette.svg?color=brightgreen" />
</a>
<a href="https://github.com/makkoncept/colorpalette/pulls">
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="prs welcome">
</a>
</p>
</p>
# Demo
<p align="center">
<img src="https://github.com/makkoncept/colorpalette/blob/master/.readme_assets/demo.gif?raw=true">
</p>
# Live
View it live at : https://colorpalettedemo.herokuapp.com/
You can deploy your own instance on heroku by clicking the following button
[](https://heroku.com/deploy)
## What it do
Extracts 10 dominating colors from the image and adds the palette to the bottom of the image (inspired by [colorpalette.cinema](https://www.instagram.com/colorpalette.cinema/?hl=en)). You can adjust the palette height, outline color, and width to match your image dimension. Another independent image of the palette with the hex codes of colors is also generated.
The app does not depend on any APIs for extracting colors. `color.py` contains the code for it with [Pillow](https://pillow.readthedocs.io/en/stable/) as the only dependency.
## Some samples
1. <span>Photo by <a href="https://unsplash.com/@lukaodak?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Luka Odak</a> on <a href="https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></span>
<p align="center">
<img width=80% src="https://i.imgur.com/zw0SenV.jpg"><br><br>
<img width=80% src="https://i.imgur.com/KNg06TY.jpg">
</p>
2. <span>Photo by <a href="https://unsplash.com/@goodspleen?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Alexandre Chambon</a> on <a href="https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></span>
<p align="center">
<img width=80% src="https://i.imgur.com/ngBiV0t.jpg"><br><br>
<img width=80% src="https://i.imgur.com/xmn52P0.jpg">
</p>
3. <span>Photo by <a href="https://unsplash.com/@federyka?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Federica Diliberto</a> on <a href="https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></span>
<p align="center">
<img height=1000px src="https://i.imgur.com/vZTtGEb.jpg"><br><br>
<img width=80% src="https://i.imgur.com/kvt0gNS.jpg">
</p>
4. <span>Photo by <a href="https://unsplash.com/@randomlies?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Ashim D’Silva</a> on <a href="https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></span>
<p align="center">
<img width=80% src="https://i.imgur.com/QCnXUAf.jpg"><br><br>
<img width=80% src="https://i.imgur.com/jjcv5OV.jpg">
</p>
## Directory Structure
<pre>
|-- Procfile
|-- README.md
|-- app.json
|-- colorpalette
| |-- __init__.py
| |-- color.py
| |-- forms.py
| |-- routes.py
| |-- static
| | |-- css
| | |-- font
| | |-- images
| | | |-- favicon
| | `-- js
| `-- templates
| |-- 413.html
| |-- base.html
| |-- index.html
| `-- picture.html
|-- config.py
|-- requirements.txt
|-- run.py
`-- LICENSE
</pre>
## Run locally
1. Clone the repostory:
```
git clone https://github.com/makkoncept/colorpalette.git
```
2. Navigate to the project root and create a virtual environment:
```
python3 -m venv venv
```
3. Activate the virtual environment:
Linux:
```
source venv/bin/activate
```
Windows cmd:
```
venv\Scripts\activate.bat
```
4. Install requirements:
```
pip install -r requirements.txt
```
5. Run the development server:
```
python run.py
```
6. View on [localhost:5000](http://127.0.0.1:5000)
## Attribution
Icon made by <a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon"> www.flaticon.com</a>
================================================
FILE: app.json
================================================
{
"name": "ColorPalette",
"description": "Extracts dominating colors from an image and present them as a palette.",
"repository": "https://github.com/makkoncept/colorpalette",
"logo": "https://raw.githubusercontent.com/makkoncept/colorpalette/master/.readme_assets/color-palette.png",
"keywords": ["Flask", "Python", "Colors"]
}
================================================
FILE: colorpalette/__init__.py
================================================
from flask import Flask
from dotenv import load_dotenv, find_dotenv
from config import Config
load_dotenv(find_dotenv())
app = Flask(__name__)
app.config.from_object(Config)
from colorpalette import routes
================================================
FILE: colorpalette/color.py
================================================
from PIL import Image, ImageDraw, ImageFont
from webcolors import rgb_to_hex
import os
def get_dominant_colors(infile):
image = Image.open(infile)
small_image = image.resize((80, 80))
result = small_image.convert(
"P", palette=Image.ADAPTIVE, colors=10
) # image with only 10 dominating colors
# Find dominant colors
palette = result.getpalette()
color_counts = sorted(result.getcolors(), reverse=True)
colors = list()
for i in range(10):
palette_index = color_counts[i][1]
dominant_color = palette[palette_index * 3 : palette_index * 3 + 3]
colors.append(tuple(dominant_color))
# print(colors)
return colors
def process_uploaded_image(
infile, outline_width, pallete_division_factor, outline_color, numcolors=10
):
# width of the pallete that will be an independent image itself
independent_pallete_width = 100
original_image = Image.open(infile)
width, height = original_image.size
# height for the pallete that will be pasted under the image
img_palette_height = int(height / pallete_division_factor)
img_palette_width = width / 10
processed_image = Image.new(
"RGB", (width, height + img_palette_height)
) # blank canvas(original image + palette)
pallete_under_image = Image.new("RGB", (width, img_palette_height))
# blank canvas for pallete. <mode, size, color>
independent_pallete = Image.new(
"RGB",
(numcolors * independent_pallete_width, independent_pallete_width + 20),
color="rgb(255, 255, 255)",
)
draw = ImageDraw.Draw(pallete_under_image)
draw2 = ImageDraw.Draw(independent_pallete)
posx = 0
posx2 = 0
fonts_path = os.path.join(
os.path.dirname(os.path.dirname(__file__)),
"colorpalette/static/font/Roboto-Bold.ttf",
)
# create font object with the font file
font = ImageFont.truetype(fonts_path, size=16)
colors = get_dominant_colors(infile)
# making the palettes
for color in colors:
draw.rectangle(
[posx, 0, posx + img_palette_width, img_palette_height],
fill=color,
width=outline_width,
outline=outline_color,
)
# drawing one pallete at a time on independent pallete canvas
draw2.rectangle(
[posx2, 0, posx2 + independent_pallete_width, independent_pallete_width],
fill=color,
)
# write the hex code under the pallete
draw2.text(
(posx2 + 20, independent_pallete_width),
rgb_to_hex(color[:3]),
fill="rgb(0, 0, 0)",
font=font,
)
# move the pointer to the beginning of next pallete color
posx = posx + img_palette_width
posx2 = posx2 + independent_pallete_width
del draw
del draw2
box = (0, height, width, height + img_palette_height)
# pasting image and palette on the canvas
processed_image.paste(original_image)
processed_image.paste(pallete_under_image, box)
return processed_image, independent_pallete
================================================
FILE: colorpalette/forms.py
================================================
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileRequired, FileAllowed
from flask_wtf.html5 import NumberInput
from wtforms import IntegerField
from wtforms.validators import NumberRange
class PhotoForm(FlaskForm):
photo = FileField(
"Upload Image", validators=[FileRequired(), FileAllowed(["jpg", "png", "jpeg"])]
)
palette_height = IntegerField(
"Palette Height", validators=[NumberRange(1, 8)], widget=NumberInput()
)
palette_outline_width = IntegerField(
"Palette Outline Width", validators=[NumberRange(1, 40)], widget=NumberInput()
)
================================================
FILE: colorpalette/routes.py
================================================
from colorpalette import app
from colorpalette.color import process_uploaded_image
from colorpalette.forms import PhotoForm
from flask import render_template, redirect, url_for, request, session
from werkzeug.utils import secure_filename
from webcolors import hex_to_rgb
import os
import uuid
@app.route("/", methods=["GET", "POST"])
def index():
form = PhotoForm()
if form.validate_on_submit():
image = form.photo.data
filename = secure_filename(image.filename) # sanitize image name
_, ext = os.path.splitext(filename)
new_filename = uuid.uuid4().hex + ext # creating a random name
image_with_palette, pallete = process_uploaded_image(
image,
pallete_division_factor=11 - form.palette_height.data,
outline_width=form.palette_outline_width.data,
outline_color=hex_to_rgb(request.form.get("palette_outline_color")),
)
image_with_pallete_path = os.path.join(
app.root_path, "static/images", new_filename
)
pallete_path = os.path.join(
app.root_path, "static/images", "pal" + new_filename
)
# saving image and pallete
image_with_palette.save(image_with_pallete_path)
pallete.save(pallete_path)
return redirect(
url_for(
"picture",
name=new_filename,
)
)
return render_template("index.html", form=form, src="default")
@app.route("/picture/<name>")
def picture(name):
processed_img_relative_path = url_for("static", filename="images/" + name)
pallete_relative_path = url_for("static", filename="images/" + "pal" + name)
return render_template(
"picture.html",
src=processed_img_relative_path,
src2=pallete_relative_path,
)
@app.errorhandler(413)
def error413(e):
return render_template("413.html"), 413
================================================
FILE: colorpalette/static/css/style.css
================================================
*,
*::before,
*::after {
padding: 0;
margin: 0;
box-sizing: border-box;
}
:root {
--primary-color: #ea538c;
--primary-color-light: #ffcde0;
}
body {
background-color: rgb(245, 245, 245);
color: #0c0c07;
font-weight: 500;
font-family: "Raleway", sans-serif;
}
h1 {
font-size: 3.3rem;
font-weight: 400;
}
h2 {
font-size: 2.5rem;
font-weight: 400;
}
.container {
padding: 2rem 5rem;
}
.image-showcase {
display: flex;
padding: 2rem 0 4rem 0;
justify-content: space-evenly;
align-items: center;
}
form {
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: center;
width: 90%;
margin: 0 auto;
}
.image-upload-wrapper {
margin: 1.5rem 0 3rem 0;
height: 11rem;
position: relative;
width: 100%;
}
.image-upload {
display: flex;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
flex-direction: column;
border: 4px dashed var(--primary-color);
border-radius: 0.5rem;
transition: background-color 0.25s ease-out;
}
.image-upload:hover {
background-color: var(--primary-color-light);
}
.image-input {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
outline: none;
cursor: pointer;
}
.image-upload-wrapper .undertext {
font-size: 0.9rem;
color: #991c19;
float: right;
}
.number-input {
width: 100%;
display: flex;
align-items: center;
padding-bottom: 1rem;
}
.number-input label {
display: inline-block;
width: 50%;
padding-right: 2rem;
font-size: 1.3rem;
text-align: right;
}
.number-input input[type="number"] {
width: 30%;
font-size: 2rem;
font-weight: 400;
padding-left: 0.6rem;
border-radius: 2px;
border: 2px solid rgb(192, 192, 192);
}
.submit-button {
color: #fff;
background-color: var(--primary-color);
border-color: var(--primary-color);
display: inline-block;
height: 2.5rem;
padding: 0 30px;
text-align: center;
font-size: 1rem;
font-weight: 600;
line-height: 38px;
letter-spacing: 0.1rem;
text-transform: uppercase;
text-decoration: none;
white-space: nowrap;
border-radius: 4px;
border: 1px solid #bbb;
cursor: pointer;
}
/* pictures.html */
.image-wrapper {
width: 70%;
margin: auto;
position: relative;
}
.image-wrapper img {
display: block;
margin: auto;
max-width: 100%;
max-height: 100%;
}
.download-image-button {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1;
opacity: 0;
color: #fff;
background-color: var(--primary-color);
font-size: 1.1rem;
font-weight: 500;
line-height: 1.1;
text-transform: capitalize;
text-decoration: none !important;
text-align: center;
border: 0 none;
border-radius: 4px;
padding: 12px 12px;
cursor: pointer;
user-select: none;
}
.download-image-button:hover {
color: #fff;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0);
transition: background 0.5s ease;
}
.image-wrapper:hover .overlay {
display: block;
background: rgba(0, 0, 0, 0.3);
}
.image-wrapper:hover .download-image-button {
opacity: 1;
}
/* github fork ribbon : https://github.com/simonwhitaker/github-fork-ribbon-css */
.github-fork-ribbon::before {
background-color: #333;
}
/* utils */
.text-align-center {
text-align: center;
}
.margin-bottom-large {
margin-bottom: 4rem;
}
.margin-bottom-normal {
margin-bottom: 2rem;
}
.margin-top-large {
margin-top: 4rem;
}
================================================
FILE: colorpalette/static/images/favicon/site.webmanifest
================================================
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
================================================
FILE: colorpalette/static/js/script.js
================================================
const imageUpload = document.querySelector(".image-upload");
const imageInput = document.querySelector(".image-input");
const imageNameDiv = document.querySelector(".image-name");
const legalFileTypes = ["image/png", "image/jpg", "image/jpeg"];
imageUpload.addEventListener("change", handleImageUpload);
function handleImageUpload(event) {
console.log(event.target.files[0]);
const FileSize = event.target.files[0].size / 1024 / 1024; // in MB
const fileType = event.target.files[0].type;
if (FileSize > 2) {
alert("File size exceeds 2 MB");
} else if (!legalFileTypes.includes(fileType)) {
alert("Only file of type 'jpeg', 'jpg', or 'png' allowed");
} else {
const imageName = event.target.files[0].name;
imageNameDiv.innerText = imageName;
}
}
================================================
FILE: colorpalette/templates/413.html
================================================
{% extends "base.html" %} {% block content %}
<div>
<h3 style="text-align: center">
Your image is too large. Please <a href="{{url_for('index')}}">upload</a> a smaller image.
</h3>
</div>
{% endblock %}
================================================
FILE: colorpalette/templates/base.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Extracts dominant colors from an image and present them as a palette." />
<meta name="author" content="Mayank Nader" />
<meta property="og:locale" content="en_US" />
<meta property="og:site_name" content="ColorPalette" />
<meta property="og:title" content="ColorPalette" />
<meta property="og:description" content="Extracts dominant colors from an image and present them as a palette." />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="ColorPalette" />
<meta name="twitter:description" content="Extracts dominant colors from an image and present them as a palette." />
<meta property="og:url" content="https://colorpalette.xyz" />
<title>ColorPalette</title>
<link rel="apple-touch-icon" sizes="180x180" href="/static/images/favicon/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/static/images/favicon/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/static/images/favicon/favicon-16x16.png" />
<link rel="icon" type="image/x-icon" href="/static/images/favicon/favicon.ico" />
<link rel="manifest" href="/static/images/favicon/site.webmanifest" />
<link href="//fonts.googleapis.com/css?family=Raleway:400,500,600" rel="stylesheet" type="text/css" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.3/gh-fork-ribbon.min.css"
/>
<link rel="stylesheet" href="/static/css/style.css" />
</head>
<body>
<a
class="github-fork-ribbon"
href="https://github.com/makkoncept/colorpalette"
data-ribbon="Fork me on GitHub"
title="Fork me on GitHub"
>Fork me on GitHub</a
>
<div class="container">{% block content %}{% endblock %}</div>
<script src="/static/js/script.js"></script>
</body>
</html>
================================================
FILE: colorpalette/templates/index.html
================================================
{% extends "base.html" %} {% block content %}
<div class="introduction text-align-center">
<h1>Color Palette</h1>
<p>Extracts dominating colors from your image</p>
</div>
<div class="image-showcase">
<img
src="{{url_for('static', filename='images/image-before-processing.jpg')}}"
width="450"
height="310"
alt="image before processing"
/>
<img src="{{url_for('static', filename='images/right-arrow.png')}}" height="115" />
<img
src="{{url_for('static', filename='images/image-after-processing.jpg')}}"
width="450"
height="310"
alt="image after processing"
/>
</div>
<h2 class="text-align-center">Try It Now</h2>
<form method="POST" enctype="multipart/form-data">
<div class="image-upload-wrapper">
{{form.hidden_tag()}}
<!-- prettier-ignore -->
<div class="image-upload">
{{form.photo(class="image-input")}}
<img src="/static/images/image-icon.png" alt="image icon">
<div class="subtitle">Upload Image</div>
<div class="image-name"></div>
{% for error in form.photo.errors %}
<span style="color: red">{{ error}}</span>
{% endfor %}
</div>
<p class="undertext">*Image size must be less than 2Mb</p>
</div>
<div class="number-input">
<label>Palette Height(1-8)</label>
{{form.palette_height(value=6, min=1, max=8)}}
<!-- prettier-ignore -->
{% for error in form.palette_height.errors %}
<span style="color: red">{{ error}}</span>
{% endfor %}
</div>
<div class="number-input">
<label>Palette Outline Width in Pixels (1-40)</label>
{{form.palette_outline_width(class="u-full-width", value=10, min=1, max=40)}}
<!-- prettier-ignore -->
{% for error in form.palette_outline_width.errors %}
<span style="color: red">{{ error}}</span>
{% endfor %}
</div>
<div class="number-input">
<label>Palette Outline color</label>
<input type="color" name="palette_outline_color" value="white" />
</div>
<input class="submit-button" type="submit" value="submit" />
</form>
{% endblock %}
================================================
FILE: colorpalette/templates/picture.html
================================================
{% extends "base.html" %} {% block content %}
<div class="text-align-center margin-bottom-large">
<h2>Try <a href="{{url_for('index')}}">Again</a>?</h2>
</div>
<div class="image-wrapper">
<img src="{{src}}" />
<div class="overlay"></div>
<a href="{{src}}" class="download-image-button" download="image-with-palette">Download Image</a>
</div>
<div>
<h2 class="margin-top-large margin-bottom-normal text-align-center">Palette with hex codes</h2>
<div class="image-wrapper">
<img src="{{src2}}" />
<div class="overlay"></div>
<a href="{{src2}}" class="download-image-button" download="palette">Download Image</a>
</div>
</div>
{% endblock %}
================================================
FILE: config.py
================================================
import os
class Config(object):
SECRET_KEY = os.environ.get("SECRET_KEY") or "N6q067SQG7894Yw28d85BqWu4"
MAX_CONTENT_LENGTH = 2 * 1024 * 1024 # image size upload limit (2 MB)
================================================
FILE: requirements.txt
================================================
Click==7.0
Flask==1.0.2
Flask-WTF==0.14.2
gunicorn==19.9.0
itsdangerous==1.1.0
Jinja2==2.10.1
MarkupSafe==1.1.1
Pillow==7.2.0
webcolors==1.8.1
Werkzeug==0.15.5
WTForms==2.2.1
python-dotenv==0.14.0
================================================
FILE: run.py
================================================
from colorpalette import app
if __name__ == "__main__":
app.run(debug=True)
gitextract_53ta_i2o/ ├── .gitignore ├── LICENSE ├── Procfile ├── README.md ├── app.json ├── colorpalette/ │ ├── __init__.py │ ├── color.py │ ├── forms.py │ ├── routes.py │ ├── static/ │ │ ├── css/ │ │ │ └── style.css │ │ ├── images/ │ │ │ └── favicon/ │ │ │ └── site.webmanifest │ │ └── js/ │ │ └── script.js │ └── templates/ │ ├── 413.html │ ├── base.html │ ├── index.html │ └── picture.html ├── config.py ├── requirements.txt └── run.py
SYMBOL INDEX (8 symbols across 5 files)
FILE: colorpalette/color.py
function get_dominant_colors (line 6) | def get_dominant_colors(infile):
function process_uploaded_image (line 27) | def process_uploaded_image(
FILE: colorpalette/forms.py
class PhotoForm (line 8) | class PhotoForm(FlaskForm):
FILE: colorpalette/routes.py
function index (line 12) | def index():
function picture (line 50) | def picture(name):
function error413 (line 62) | def error413(e):
FILE: colorpalette/static/js/script.js
function handleImageUpload (line 8) | function handleImageUpload(event) {
FILE: config.py
class Config (line 4) | class Config(object):
Condensed preview — 19 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (24K chars).
[
{
"path": ".gitignore",
"chars": 71,
"preview": "venv/\nvenv\n__pycache__/\ncolorpalette/__pycache__\n.idea\n*.pyc\n.vscode/\n\n"
},
{
"path": "LICENSE",
"chars": 1069,
"preview": "MIT License\n\nCopyright (c) 2018 Mayank Nader\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
},
{
"path": "Procfile",
"chars": 31,
"preview": "web: gunicorn colorpalette:app\n"
},
{
"path": "README.md",
"chars": 4478,
"preview": "<p align=\"center\">\n <img height=200 src=\"https://github.com/makkoncept/colorpalette/blob/master/.readme_assets/color-pa"
},
{
"path": "app.json",
"chars": 339,
"preview": "{\n \"name\": \"ColorPalette\",\n \"description\": \"Extracts dominating colors from an image and present them as a palette.\",\n"
},
{
"path": "colorpalette/__init__.py",
"chars": 210,
"preview": "from flask import Flask\nfrom dotenv import load_dotenv, find_dotenv\nfrom config import Config\n\nload_dotenv(find_dotenv()"
},
{
"path": "colorpalette/color.py",
"chars": 3108,
"preview": "from PIL import Image, ImageDraw, ImageFont\nfrom webcolors import rgb_to_hex\nimport os\n\n\ndef get_dominant_colors(infile)"
},
{
"path": "colorpalette/forms.py",
"chars": 615,
"preview": "from flask_wtf import FlaskForm\nfrom flask_wtf.file import FileField, FileRequired, FileAllowed\nfrom flask_wtf.html5 imp"
},
{
"path": "colorpalette/routes.py",
"chars": 1918,
"preview": "from colorpalette import app\nfrom colorpalette.color import process_uploaded_image\nfrom colorpalette.forms import PhotoF"
},
{
"path": "colorpalette/static/css/style.css",
"chars": 3521,
"preview": "*,\n*::before,\n*::after {\n padding: 0;\n margin: 0;\n box-sizing: border-box;\n}\n\n:root {\n --primary-color: #ea538c;\n -"
},
{
"path": "colorpalette/static/images/favicon/site.webmanifest",
"chars": 263,
"preview": "{\"name\":\"\",\"short_name\":\"\",\"icons\":[{\"src\":\"/android-chrome-192x192.png\",\"sizes\":\"192x192\",\"type\":\"image/png\"},{\"src\":\"/"
},
{
"path": "colorpalette/static/js/script.js",
"chars": 778,
"preview": "const imageUpload = document.querySelector(\".image-upload\");\nconst imageInput = document.querySelector(\".image-input\");\n"
},
{
"path": "colorpalette/templates/413.html",
"chars": 211,
"preview": "{% extends \"base.html\" %} {% block content %}\n<div>\n <h3 style=\"text-align: center\">\n Your image is too large. Pleas"
},
{
"path": "colorpalette/templates/base.html",
"chars": 2058,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-w"
},
{
"path": "colorpalette/templates/index.html",
"chars": 2116,
"preview": "{% extends \"base.html\" %} {% block content %}\n<div class=\"introduction text-align-center\">\n <h1>Color Palette</h1>\n <p"
},
{
"path": "colorpalette/templates/picture.html",
"chars": 668,
"preview": "{% extends \"base.html\" %} {% block content %}\n\n<div class=\"text-align-center margin-bottom-large\">\n <h2>Try <a href=\"{{"
},
{
"path": "config.py",
"chars": 186,
"preview": "import os\n\n\nclass Config(object):\n SECRET_KEY = os.environ.get(\"SECRET_KEY\") or \"N6q067SQG7894Yw28d85BqWu4\"\n MAX_C"
},
{
"path": "requirements.txt",
"chars": 197,
"preview": "Click==7.0\nFlask==1.0.2\nFlask-WTF==0.14.2\ngunicorn==19.9.0\nitsdangerous==1.1.0\nJinja2==2.10.1\nMarkupSafe==1.1.1\nPillow=="
},
{
"path": "run.py",
"chars": 81,
"preview": "from colorpalette import app\n\nif __name__ == \"__main__\":\n app.run(debug=True)\n"
}
]
About this extraction
This page contains the full source code of the makkoncept/colorpalette GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 19 files (21.4 KB), approximately 6.4k tokens, and a symbol index with 8 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.