86 Commits

Author SHA1 Message Date
5119d4bb31 Merge branch 'main' of https://gitea.sekidesu.xyz/SekiDesu01/SekiPOS 2026-03-13 21:55:23 -03:00
acaf537f11 reverese engeneering of TM1621 display 2026-03-13 21:54:45 -03:00
55ff314163 Merge branch 'main' of https://gitea.sekidesu.xyz/SekiDesu01/SekiPOS 2026-03-13 18:07:54 -03:00
376b8c54a6 Version bump to v2.0, updated checkout and dicom 2026-03-13 18:07:09 -03:00
1a048a0e07 Fixed recepit lenght 2026-03-11 16:52:17 -03:00
77fc5920a2 image export like db 2026-03-11 15:59:50 -03:00
78d48db9ea added image_url column to dicom table 2026-03-10 23:39:44 -03:00
92e3a3f0f9 dicom evidence update 2026-03-10 23:22:50 -03:00
57cb27f6cf db dump tool 2026-03-10 22:47:40 -03:00
c24dae9694 actions button position fix 2026-03-10 22:41:34 -03:00
e0ac23a8e0 re-print old receipt from sales page 2026-03-10 22:37:47 -03:00
c1a06dc44c allow for inmediate confimation of checkout 2026-03-10 22:32:37 -03:00
72f6e0c822 receipt print fix 2026-03-10 22:25:09 -03:00
b2418d8c7e style fixes 2026-03-10 22:15:18 -03:00
9cb057668b login style fix 2026-03-10 21:41:15 -03:00
cb2aa89b16 WIP rewrite with macros 2026-03-10 20:15:58 -03:00
ef9a9296dd initial modularization + templates 2026-03-10 18:40:47 -03:00
3c4b2e148d Implemented Dicom 2026-03-09 18:25:49 -03:00
bf1bc84cd0 Checkout UI fixes 2026-03-09 16:54:55 -03:00
8e37f9e776 Implemented change calculator and various UI fixes 2026-03-09 16:32:23 -03:00
216abc8ad2 Fixed receipt design 2026-03-09 13:02:00 -03:00
cffa3d789b modified: templates/checkout.html 2026-03-09 11:34:49 -03:00
d7ef1573e5 modified: templates/checkout.html 2026-03-09 10:20:59 -03:00
e101833c7d modified: templates/checkout.html 2026-03-09 09:53:30 -03:00
6c98919c80 Added option forcustom product during checkout 2026-03-09 07:00:47 -03:00
cae35a266f Implemented receipt generation and printing 2026-03-09 06:20:24 -03:00
c57e8ab6db Implemented sales dashboard 2026-03-09 05:58:24 -03:00
135b14adcf Added persistent cart for chechout 2026-03-09 05:06:25 -03:00
9f59e122ef Various chechout improvements: subtotal rounding, placeholder color, and weight input now in grams for better UX. 2026-03-09 03:53:28 -03:00
43cc2a3caa Fixed UI inconsistencies and added logic to handle unit types in the product list and form. Also added a call to toggle the stock input visibility on page load based on the default unit type. 2026-03-09 02:55:07 -03:00
shironeko
2f2998b0fd esp attempt, stock + unit type 2026-03-07 19:21:14 -03:00
788b67804e oops 2026-03-07 03:35:22 -03:00
2bb38570f9 deactivated MP stuff 2026-03-07 03:23:00 -03:00
aacbce2557 oops 2026-03-07 03:07:55 -03:00
6c5085093d chekout update, mp study v1 2026-03-07 03:07:45 -03:00
423d563cc0 image compression, initial checkout(? 2026-03-04 22:47:02 -03:00
5e79b6938c delimiter character setup + extended api data 2026-03-01 03:54:05 -03:00
dcd14f1021 Scanner with LF thing to prevent partial scanning 2026-03-01 03:45:37 -03:00
b4344361e4 adding data to scan request + Go ARMv7 2026-03-01 03:23:53 -03:00
fcb75cb5a4 settings file for scanner 2026-03-01 02:21:17 -03:00
676f299796 version bump 2026-02-28 22:41:33 -03:00
751c77cac5 zoom + flash + focus = scanning improvements for iphone and android 2026-02-28 22:39:57 -03:00
85b2c0b4db more theme and camera fixes TwT 2026-02-27 01:11:54 -03:00
741690b30e X fix 2026-02-27 01:06:42 -03:00
7235c7ff09 theme and camera cookie 2026-02-27 00:57:45 -03:00
8cba7937c3 image cache fix 2026-02-27 00:29:25 -03:00
4779452acd image timestamp fix 2026-02-27 00:16:43 -03:00
600df52b04 camera index? 2026-02-27 00:03:55 -03:00
b1b99bc887 webui camera barcode scanner 2026-02-26 23:59:22 -03:00
c7c0b3feb2 picture qol fixes 2026-02-26 23:55:49 -03:00
184f2722bf sort table 2026-02-26 23:38:55 -03:00
0f9966d224 qol and scan fixes 2026-02-26 23:29:45 -03:00
43b2a9e2d5 version bump :p 2026-02-26 22:53:44 -03:00
3a39cb95db re-retriede image if cached one doesnt exist anymore 2026-02-26 22:52:34 -03:00
81cacd3589 bulk delete + more prompts 2026-02-26 22:50:20 -03:00
1f521ec1d2 colors and prompts fix 2026-02-26 22:33:38 -03:00
0dcf0bc930 modified: static/styleIndex.css
modified:   templates/index.html
2026-02-26 21:46:42 -03:00
df4ff9171d Merge branch 'main' of https://gitea.sekidesu.xyz/SekiDesu01/SekiPOS 2026-02-26 21:16:41 -03:00
1b2e63bc86 added bulk price update feature, allowing users to select multiple products and apply a new price to all of them at once. The bulk action bar now shows the count of selected items and enables the "OK" button only when at least one product is selected. 2026-02-26 21:16:16 -03:00
80bf539484 Merge branch 'main' of https://gitea.sekidesu.xyz/SekiDesu01/SekiPOS 2026-02-26 20:48:56 -03:00
13bba33c26 modified: templates/index.html 2026-02-26 04:21:20 -03:00
ecd98c72ce new file: ScannerPython/output/scannerV2.exe
new file:   ScannerPython/scannerV2.py
2026-02-26 04:10:48 -03:00
344229b77b bump version 2026-02-26 03:35:34 -03:00
9a28daa2cd fill edit fileds on scan 2026-02-26 03:33:45 -03:00
ebf8bc72aa fix custom images cache 2026-02-26 03:30:23 -03:00
2ef510358d cache image not being used fixed 2026-02-26 03:22:05 -03:00
d492905e57 todos 2026-02-26 03:06:07 -03:00
7a4d122976 file organization of htmls css 2026-02-26 03:02:03 -03:00
8cc5138888 discord theme, top bar fix, organized folders 2026-02-26 02:55:20 -03:00
3f47b3cda4 new file: KeyGenerator/A4 Printable Grid.py
new file:   keychain_3x3_perfect.pdf
2026-02-26 02:39:05 -03:00
c1045b4878 path python fix 2026-02-26 02:37:07 -03:00
70c14acaa5 dark mode + reorganization 2026-02-26 02:29:23 -03:00
2701dfbf85 Merge branch 'main' of https://gitea.sekidesu.xyz/SekiDesu01/SekiPOS 2026-02-26 02:26:09 -03:00
6aa3421f0c tajetitas 2026-02-26 02:25:48 -03:00
b6cc945adb Merge branch 'main' of https://gitea.sekidesu.xyz/SekiDesu01/SekiPOS 2026-02-26 02:00:58 -03:00
a22d808b7b modified: README.md 2026-02-26 01:59:16 -03:00
3198696c46 new file: KeyGenerator/generate_keys.py 2026-02-26 00:46:51 -03:00
a90efc621d oops typo :3 2026-02-26 00:35:22 -03:00
d8b710805f docker FIX 2026-02-26 00:34:36 -03:00
1e6778f2bf modified: Dockerfile 2026-02-26 00:25:32 -03:00
574ee7773c modified: Dockerfile 2026-02-26 00:24:16 -03:00
fbb868c244 dockerfile v2 2026-02-26 00:19:59 -03:00
3a68431a21 finish 2026-02-26 00:10:36 -03:00
ad0fb66b7a modified: README.md 2026-02-26 00:09:41 -03:00
788867c1af new file: ScannerPython/scanner.py 2026-02-26 00:04:55 -03:00
a695640009 modified: README.md 2026-02-26 00:03:39 -03:00
204 changed files with 6001 additions and 326 deletions

6
.gitignore vendored
View File

@@ -1 +1,5 @@
pos_database.db
pos_database.db
ScannerGO/ScannerGO-*
ScannerGO/config.json
DataToolsGO/imageTools-*
.env

11
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Build SekiPOS (F5)",
"type": "node",
"request": "launch",
"preLaunchTask": "build-sekipos"
}
]
}

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"python-envs.defaultEnvManager": "ms-python.python:pyenv"
}

15
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,15 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build-sekipos",
"type": "shell",
"command": "docker build -t sekipos:latest .",
"group": "build",
"presentation": {
"reveal": "always",
"panel": "new"
}
}
]
}

42
DataToolsGO/build.sh Executable file
View File

@@ -0,0 +1,42 @@
#!/bin/bash
# Define binary names
LINUX_BIN="imageTools-linux"
LINUX_ARM_BIN="imageTools-linuxARMv7"
WINDOWS_BIN="imageTools-windows.exe"
echo "Starting build process..."
# Build for Linux (64-bit)
echo "Building for Linux..."
GOOS=linux GOARCH=amd64 go build -o "$LINUX_BIN" main.go
if [ $? -eq 0 ]; then
echo "Successfully built: $LINUX_BIN"
else
echo "Failed to build Linux binary"
exit 1
fi
# Build for Windows (64-bit)
echo "Building for Windows..."
GOOS=windows GOARCH=amd64 go build -o "$WINDOWS_BIN" main.go
if [ $? -eq 0 ]; then
echo "Successfully built: $WINDOWS_BIN"
else
echo "Failed to build Windows binary"
exit 1
fi
# Build for Linux ARM (ARMv7)
echo "Building for Linux ARMv7..."
GOOS=linux GOARCH=arm GOARM=7 go build -o "$LINUX_ARM_BIN" main.go
if [ $? -eq 0 ]; then
echo "Successfully built: $LINUX_ARM_BIN"
else
echo "Failed to build Linux ARMv7 binary"
exit 1
fi
echo "Build complete."

5
DataToolsGO/go.mod Normal file
View File

@@ -0,0 +1,5 @@
module dataTools
go 1.25.7
require github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646

2
DataToolsGO/go.sum Normal file
View File

@@ -0,0 +1,2 @@
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=

84
DataToolsGO/main.go Normal file
View File

@@ -0,0 +1,84 @@
package main
import (
"flag"
"fmt"
"image"
"image/jpeg"
"os"
"path/filepath"
"strings"
"github.com/nfnt/resize"
)
func main() {
// Command line arguments
dirPath := flag.String("dir", "./", "Directory containing images")
maxWidth := flag.Uint("width", 1000, "Maximum width for resizing")
quality := flag.Int("quality", 75, "JPEG quality (1-100)")
flag.Parse()
files, err := os.ReadDir(*dirPath)
if err != nil {
fmt.Printf("Error reading directory: %v\n", err)
return
}
fmt.Printf("Processing images in %s (Max Width: %d, Quality: %d)\n", *dirPath, *maxWidth, *quality)
for _, file := range files {
if file.IsDir() {
continue
}
ext := strings.ToLower(filepath.Ext(file.Name()))
if ext != ".jpg" && ext != ".jpeg" && ext != ".png" {
continue
}
filePath := filepath.Join(*dirPath, file.Name())
processImage(filePath, *maxWidth, *quality)
}
fmt.Println("Done. Your storage can finally breathe again.")
}
func processImage(path string, maxWidth uint, quality int) {
file, err := os.Open(path)
if err != nil {
fmt.Printf("Failed to open %s: %v\n", path, err)
return
}
img, _, err := image.Decode(file)
file.Close()
if err != nil {
fmt.Printf("Failed to decode %s: %v\n", path, err)
return
}
// Only resize if original is wider than maxWidth
bounds := img.Bounds()
var finalImg image.Image
if uint(bounds.Dx()) > maxWidth {
finalImg = resize.Resize(maxWidth, 0, img, resize.Lanczos3)
fmt.Printf("Resized and compressed: %s\n", filepath.Base(path))
} else {
finalImg = img
fmt.Printf("Compressed (no resize needed): %s\n", filepath.Base(path))
}
// Overwrite the original file
out, err := os.Create(path)
if err != nil {
fmt.Printf("Failed to create output file %s: %v\n", path, err)
return
}
defer out.Close()
err = jpeg.Encode(out, finalImg, &jpeg.Options{Quality: quality})
if err != nil {
fmt.Printf("Failed to encode %s: %v\n", path, err)
}
}

View File

@@ -2,10 +2,22 @@ FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt ./
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# Copy source code
COPY app.py .
COPY templates/ ./templates/
COPY static/ ./static/
#COPY .env .
# Create the folder structure for the volume mounts
RUN mkdir -p /app/static/cache
EXPOSE 5000
# Run with unbuffered output so you can actually see the logs in Portainer
ENV PYTHONUNBUFFERED=1
CMD ["python", "app.py"]

View File

@@ -0,0 +1,70 @@
import os
from PIL import Image
# --- CONFIGURATION ---
CARD_DIR = os.path.join(os.getcwd(),'keychain_cards')
OUTPUT_PDF = os.path.join(os.getcwd(), 'keychain_3x3_perfect.pdf')
# A4 at 300 DPI
PAGE_W, PAGE_H = 2480, 3508
COLS, ROWS = 3, 3 # 9 cards per page
PAGE_MARGIN = 150
def generate_printable_pdf():
all_files = [f for f in os.listdir(CARD_DIR) if f.endswith('.png')]
if not all_files:
print("❌ No cards found.")
return
all_files.sort()
# Calculate slot size
available_w = PAGE_W - (PAGE_MARGIN * 2)
available_h = PAGE_H - (PAGE_MARGIN * 2)
slot_w = available_w // COLS
slot_h = available_h // ROWS
# TARGET CALCULATION (Maintain 300:450 ratio)
# We fit to the width of the slot and let height follow
target_w = int(slot_w * 0.9)
target_h = int(target_w * (450 / 300)) # Maintain original 1:1.5 ratio
# Safety check: if height is too big for slot, scale down based on height instead
if target_h > (slot_h * 0.9):
target_h = int(slot_h * 0.9)
target_w = int(target_h * (300 / 450))
pages = []
current_page = Image.new('RGB', (PAGE_W, PAGE_H), 'white')
print(f"📄 Generating {COLS}x{ROWS} grid. {len(all_files)} cards total.")
for i, filename in enumerate(all_files):
item_idx = i % (COLS * ROWS)
# New page logic
if item_idx == 0 and i > 0:
pages.append(current_page)
current_page = Image.new('RGB', (PAGE_W, PAGE_H), 'white')
row = item_idx // COLS
col = item_idx % COLS
img_path = os.path.join(CARD_DIR, filename)
card_img = Image.open(img_path).convert('RGB')
# Resize using the aspect-ratio-safe dimensions
card_img = card_img.resize((target_w, target_h), Image.Resampling.LANCZOS)
# Center in slot
x = PAGE_MARGIN + (col * slot_w) + (slot_w - target_w) // 2
y = PAGE_MARGIN + (row * slot_h) + (slot_h - target_h) // 2
current_page.paste(card_img, (x, y))
pages.append(current_page)
pages[0].save(OUTPUT_PDF, save_all=True, append_images=pages[1:], resolution=300.0, quality=100)
print(f"✅ Created {OUTPUT_PDF}. Now go print it and stop crying.")
if __name__ == "__main__":
generate_printable_pdf()

Binary file not shown.

View File

@@ -0,0 +1,51 @@
import pandas as pd
import json
import os
file_path = os.path.join(os.getcwd(), 'PLU+FSMA+list+v1.0.xlsx')
sheet_name = 'Non FTL'
new_url_base = "https://server-ifps.accurateig.com/assets/commodities/"
def get_one_of_each():
if not os.path.exists(file_path):
print("❌ Excel file not found.")
return
# 1. Load Excel
df = pd.read_excel(file_path, sheet_name=sheet_name)
# 2. Drop rows missing the essentials
df = df.dropna(subset=['IMAGE', 'PLU', 'COMMODITY'])
# 3. CRITICAL: Drop duplicates by COMMODITY only
# This ignores Variety and Size, giving us exactly one row per fruit type.
df_unique = df.drop_duplicates(subset=['COMMODITY'], keep='first')
data_output = []
for _, row in df_unique.iterrows():
# Extract filename from the messy URL in Excel
original_link = str(row['IMAGE'])
filename = original_link.split('/')[-1]
# Build the final working URL
image_url = f"{new_url_base}{filename}"
# Get the clean Commodity name
commodity = str(row['COMMODITY']).title()
plu_code = str(row['PLU'])
data_output.append({
"name": commodity,
"plu": plu_code,
"image": image_url
})
# 4. Save to JSON
with open('one_of_each.json', 'w', encoding='utf-8') as f:
json.dump(data_output, f, indent=4, ensure_ascii=False)
print(f"✅ Success! Generated 'one_of_each.json' with {len(data_output)} unique commodities.")
if __name__ == "__main__":
get_one_of_each()

437
KeyGenerator/frutas.json Normal file
View File

@@ -0,0 +1,437 @@
[
{
"name": "Almendras",
"plu": "4924",
"image": "https://server-ifps.accurateig.com/assets/commodities/4924-almonds_1630598936.jpg"
},
{
"name": "Manzanas",
"plu": "4099",
"image": "https://server-ifps.accurateig.com/assets/commodities/apples-akane_1629314651.png"
},
{
"name": "Damascos",
"plu": "3044",
"image": "https://server-ifps.accurateig.com/assets/commodities/3044-apricots-black-velvet-03_1614619576.jpg"
},
{
"name": "Alcachofas",
"plu": "4519",
"image": "https://server-ifps.accurateig.com/assets/commodities/4519-artichokes-baby-02_1625671366.jpg"
},
{
"name": "Espárragos",
"plu": "4521",
"image": "https://server-ifps.accurateig.com/assets/commodities/4521-asparagus-01_1625671446.jpg"
},
{
"name": "Paltas",
"plu": "3509",
"image": "https://server-ifps.accurateig.com/assets/commodities/3509-gem-avocado_1625011346.JPG"
},
{
"name": "Babaco",
"plu": "3303",
"image": "https://server-ifps.accurateig.com/assets/commodities/3303-babacoa_1614719281.JPG"
},
{
"name": "Plátanos",
"plu": "4235",
"image": "https://server-ifps.accurateig.com/assets/commodities/4235-plantains-01_1625076376.jpg"
},
{
"name": "Porotos verdes / Porotos",
"plu": "4527",
"image": "https://server-ifps.accurateig.com/assets/commodities/4527-beans-chinese-long-07_1625671743.jpg"
},
{
"name": "Betarragas",
"plu": "4537",
"image": "https://server-ifps.accurateig.com/assets/commodities/4537-baby-golden-beets_1635173500.jpg"
},
{
"name": "Moras / Berries",
"plu": "4239",
"image": "https://server-ifps.accurateig.com/assets/commodities/4239-berries-blackberries-01_1625076478.jpg"
},
{
"name": "Nueces de Brasil",
"plu": "4926",
"image": "https://server-ifps.accurateig.com/assets/commodities/4926-brazil-nuts-02_1625756785.JPG"
},
{
"name": "Repollo",
"plu": "4069",
"image": "https://server-ifps.accurateig.com/assets/commodities/4069-green-cabbage_1633958066.jpg"
},
{
"name": "Zanahorias",
"plu": "4560",
"image": "https://server-ifps.accurateig.com/assets/commodities/4560-carrots-baby_1625673556.jpg"
},
{
"name": "Castañas de cajú",
"plu": "3105",
"image": "https://server-ifps.accurateig.com/assets/commodities/3105-cashews-03_1614635878.JPG"
},
{
"name": "Apionabo",
"plu": "3321",
"image": "https://server-ifps.accurateig.com/assets/commodities/3321-celery-root-03_1614720213.jpg"
},
{
"name": "Cerezas",
"plu": "3549",
"image": "https://server-ifps.accurateig.com/assets/commodities/screenshot-2023-05-02-100428_1683036305.png"
},
{
"name": "Castañas",
"plu": "4927",
"image": "https://server-ifps.accurateig.com/assets/commodities/4927-chestnuts-italian-02_1625756943.jpg"
},
{
"name": "Cocos",
"plu": "4261",
"image": "https://server-ifps.accurateig.com/assets/commodities/4261-coconuts-02_1625077777.jpg"
},
{
"name": "Choclo",
"plu": "3087",
"image": "https://server-ifps.accurateig.com/assets/commodities/3087-corn-04_1614633780.jpg"
},
{
"name": "Dátiles",
"plu": "4862",
"image": "https://server-ifps.accurateig.com/assets/commodities/4862-dates_1630598790.jpg"
},
{
"name": "Eneldo",
"plu": "4892",
"image": "https://server-ifps.accurateig.com/assets/commodities/4892-dill-baby-02_1625755376.jpg"
},
{
"name": "Berenjena",
"plu": "4599",
"image": "https://server-ifps.accurateig.com/assets/commodities/4599-baby-eggplant-aubergine_1633372314.jpg"
},
{
"name": "Helechos",
"plu": "4606",
"image": "https://server-ifps.accurateig.com/assets/commodities/4606-fiddlehead-ferns-07_1625679559.jpg"
},
{
"name": "Higos",
"plu": "4266",
"image": "https://server-ifps.accurateig.com/assets/commodities/4266-figs-03_1625077969.jpg"
},
{
"name": "Ajo",
"plu": "4608",
"image": "https://server-ifps.accurateig.com/assets/commodities/4608-garlic-regular_1637184640.jpg"
},
{
"name": "Jengibre",
"plu": "4612",
"image": "https://server-ifps.accurateig.com/assets/commodities/4612-ginger-root-06_1625679690.jpg"
},
{
"name": "Bardana",
"plu": "3091",
"image": "https://server-ifps.accurateig.com/assets/commodities/3091gobo-root-02_1614634374.jpg"
},
{
"name": "Pomelo",
"plu": "4279",
"image": "https://server-ifps.accurateig.com/assets/commodities/4279-pummelos-02_1625078575.jpg"
},
{
"name": "Uvas",
"plu": "3491",
"image": "https://server-ifps.accurateig.com/assets/commodities/arra-15-grape_1518122851.JPG"
},
{
"name": "Hojas de col / Verdes",
"plu": "4614",
"image": "https://server-ifps.accurateig.com/assets/commodities/4614-collard-greens-trimmed_1625679839.JPG"
},
{
"name": "Rábano picante",
"plu": "4625",
"image": "https://server-ifps.accurateig.com/assets/commodities/4625-horseradish-root-04_1625680026.jpg"
},
{
"name": "Jícama",
"plu": "4626",
"image": "https://server-ifps.accurateig.com/assets/commodities/4626-jicama_1635179919.jpg"
},
{
"name": "Kiwi",
"plu": "3279",
"image": "https://server-ifps.accurateig.com/assets/commodities/3279-kiwi-gold-03_1614718637.jpg"
},
{
"name": "Kumquat",
"plu": "4303",
"image": "https://server-ifps.accurateig.com/assets/commodities/4303-kumquats-03_1625079229.jpg"
},
{
"name": "Puerros",
"plu": "4629",
"image": "https://server-ifps.accurateig.com/assets/commodities/4629-leeks-02_1625680225.jpg"
},
{
"name": "Limones",
"plu": "3626",
"image": "https://server-ifps.accurateig.com/assets/commodities/3626-meyer-lemons_1460404763.jpg"
},
{
"name": "Limequats",
"plu": "4328",
"image": "https://server-ifps.accurateig.com/assets/commodities/4328-limequats-01_1625081231.jpg"
},
{
"name": "Limas",
"plu": "4305",
"image": "https://server-ifps.accurateig.com/assets/commodities/4305-limes-key-03_1625079363.jpg"
},
{
"name": "Nísperos",
"plu": "4308",
"image": "https://server-ifps.accurateig.com/assets/commodities/4308-lychees-5_1625079574.jpg"
},
{
"name": "Raíz de loto",
"plu": "3099",
"image": "https://server-ifps.accurateig.com/assets/commodities/3099-lotus-root-03_1614635240.jpg"
},
{
"name": "Macadamia",
"plu": "3106",
"image": "https://server-ifps.accurateig.com/assets/commodities/3106-macadamias_1614705972.JPG"
},
{
"name": "Malanga",
"plu": "4644",
"image": "https://server-ifps.accurateig.com/assets/commodities/4644-malanga_1633956612.jpg"
},
{
"name": "Menta",
"plu": "3475",
"image": "https://server-ifps.accurateig.com/assets/commodities/peppermint-3475_1625790587.jpg"
},
{
"name": "Hongos / Callampas",
"plu": "4647",
"image": "https://server-ifps.accurateig.com/assets/commodities/4647-mushrooms-chanterelles-1_1625681503.jpg"
},
{
"name": "Ñame",
"plu": "3276",
"image": "https://server-ifps.accurateig.com/assets/commodities/3276-name-white_1634146226.jpg"
},
{
"name": "Nectarinas",
"plu": "3437",
"image": "https://server-ifps.accurateig.com/assets/commodities/yellow-fleshed-flat-nectarine_1629140965.jpg"
},
{
"name": "Cebollines / Cebollas",
"plu": "4068",
"image": "https://server-ifps.accurateig.com/assets/commodities/4068-onions-green-2_1625063600.jpg"
},
{
"name": "Naranjas",
"plu": "4381",
"image": "https://server-ifps.accurateig.com/assets/commodities/4381-oranges-blood-01_1625082045.jpg"
},
{
"name": "Chirivía",
"plu": "4672",
"image": "https://server-ifps.accurateig.com/assets/commodities/4672-parsnip_1633958885.jpg"
},
{
"name": "Maracuyá",
"plu": "3311",
"image": "https://server-ifps.accurateig.com/assets/commodities/3311-passion-fruit-02_1614719436.jpg"
},
{
"name": "Duraznos",
"plu": "3113",
"image": "https://server-ifps.accurateig.com/assets/commodities/3113-peaches-donut-04_1614707155.jpg"
},
{
"name": "Maníes",
"plu": "4931",
"image": "https://server-ifps.accurateig.com/assets/commodities/4931-peanuts_1625757234.JPG"
},
{
"name": "Peras",
"plu": "3317",
"image": "https://server-ifps.accurateig.com/assets/commodities/3317-angelys-pear_1460402454.jpg"
},
{
"name": "Arvejas",
"plu": "4673",
"image": "https://server-ifps.accurateig.com/assets/commodities/4673-peas-black-eyed-01_1625684339.jpg"
},
{
"name": "Nueces pecán",
"plu": "4936",
"image": "https://server-ifps.accurateig.com/assets/commodities/4936-pecans-01_1625757366.JPG"
},
{
"name": "Caqui",
"plu": "4428",
"image": "https://server-ifps.accurateig.com/assets/commodities/4428-persimmons-fuyu-01_1625667410.jpg"
},
{
"name": "Physalis",
"plu": "3039",
"image": "https://server-ifps.accurateig.com/assets/commodities/3039-cape-gooseberry_1630596655.jpg"
},
{
"name": "Piña",
"plu": "4430",
"image": "https://server-ifps.accurateig.com/assets/commodities/4430-pineapple-05_1625667649.jpg"
},
{
"name": "Pistacho",
"plu": "4939",
"image": "https://server-ifps.accurateig.com/assets/commodities/4939-pistachios_1625757519.JPG"
},
{
"name": "Pitahaya",
"plu": "3040",
"image": "https://server-ifps.accurateig.com/assets/commodities/3040-pitaya-dragon-fruit-01_1614282658.jpg"
},
{
"name": "Plumcot",
"plu": "3611",
"image": "https://server-ifps.accurateig.com/assets/commodities/interspecific-plum-black-picture_1629142350.JPG"
},
{
"name": "Ciruelas",
"plu": "4435",
"image": "https://server-ifps.accurateig.com/assets/commodities/4435-plums-greengage-01_1625667846.jpg"
},
{
"name": "Granada",
"plu": "3440",
"image": "https://server-ifps.accurateig.com/assets/commodities/3440-large-pomegranate_1486484749.JPG"
},
{
"name": "Papas",
"plu": "3414",
"image": "https://server-ifps.accurateig.com/assets/commodities/3414-baking-potato-white_1635179333.jpg"
},
{
"name": "Zapallo",
"plu": "4734",
"image": "https://server-ifps.accurateig.com/assets/commodities/4734-mini-pumpkin_1633964765.jpg"
},
{
"name": "Guía de zapallo",
"plu": "3480",
"image": "https://server-ifps.accurateig.com/assets/commodities/pumpkin-vine-3480_1625790222.jpg"
},
{
"name": "Quelites",
"plu": "3478",
"image": "https://server-ifps.accurateig.com/assets/commodities/quelite-3478_1625790359.jpg"
},
{
"name": "Membrillo",
"plu": "4447",
"image": "https://server-ifps.accurateig.com/assets/commodities/4447-quince-1_1625668926.jpg"
},
{
"name": "Radicchio",
"plu": "3168",
"image": "https://server-ifps.accurateig.com/assets/commodities/3168-radicchio-castelfranco-02_1614718366.jpg"
},
{
"name": "Rábanos",
"plu": "4739",
"image": "https://server-ifps.accurateig.com/assets/commodities/4739-radish-black-03_1625751544.jpg"
},
{
"name": "Ruibarbo",
"plu": "4745",
"image": "https://server-ifps.accurateig.com/assets/commodities/4745-rhubarb-01_1625751764.jpg"
},
{
"name": "Rutabagas",
"plu": "4747",
"image": "https://server-ifps.accurateig.com/assets/commodities/4747-rutabaga_1635168852.jpg"
},
{
"name": "Zapote",
"plu": "3137",
"image": "https://server-ifps.accurateig.com/assets/commodities/3137-sapote-white_1635264028.jpg"
},
{
"name": "Zapallo italiano / Zapallo",
"plu": "4750",
"image": "https://server-ifps.accurateig.com/assets/commodities/4750-squash-acorn-01_1625751871.jpg"
},
{
"name": "Caña de azúcar",
"plu": "4790",
"image": "https://server-ifps.accurateig.com/assets/commodities/4790-sugar-cane_1630598686.jpg"
},
{
"name": "Tupinambo",
"plu": "4791",
"image": "https://server-ifps.accurateig.com/assets/commodities/4791-sunchokes-03_1625753005.jpg"
},
{
"name": "Semillas de maravilla",
"plu": "4942",
"image": "https://server-ifps.accurateig.com/assets/commodities/4942-sunflower-seeds_1630599026.jpg"
},
{
"name": "Camote",
"plu": "4816",
"image": "https://server-ifps.accurateig.com/assets/commodities/4816-sweet-potatoes-02_1625754367.jpg"
},
{
"name": "Tamarindo",
"plu": "4448",
"image": "https://server-ifps.accurateig.com/assets/commodities/4448-tamarindo-01_1625669100.jpg"
},
{
"name": "Mandarinas",
"plu": "3524",
"image": "https://server-ifps.accurateig.com/assets/commodities/noble-juicycrunch-productisolated-900x900-rgb-copy_1627662136.png"
},
{
"name": "Taro",
"plu": "4795",
"image": "https://server-ifps.accurateig.com/assets/commodities/4795-taro-root-01_1625753179.jpg"
},
{
"name": "Nabo",
"plu": "4811",
"image": "https://server-ifps.accurateig.com/assets/commodities/4811-turnip-purple-top_1635177577.jpg"
},
{
"name": "Nueces",
"plu": "4943",
"image": "https://server-ifps.accurateig.com/assets/commodities/4943-walnuts_1625757652.JPG"
},
{
"name": "Castañas de agua",
"plu": "4814",
"image": "https://server-ifps.accurateig.com/assets/commodities/4814-waterchestnuts-01_1625753939.jpg"
},
{
"name": "Xpelón",
"plu": "3481",
"image": "https://server-ifps.accurateig.com/assets/commodities/expelon-3481_1625790150.jpg"
},
{
"name": "Yuca",
"plu": "4819",
"image": "https://server-ifps.accurateig.com/assets/commodities/4819-yucca-root-03_1625754507.jpg"
}
]

162
KeyGenerator/frutas2.json Normal file
View File

@@ -0,0 +1,162 @@
[
{
"name": "Paltas",
"plu": "3509",
"image": "https://server-ifps.accurateig.com/assets/commodities/3509-gem-avocado_1625011346.JPG"
},
{
"name": "Papas",
"plu": "3414",
"image": "https://server-ifps.accurateig.com/assets/commodities/3414-baking-potato-white_1635179333.jpg"
},
{
"name": "Limones",
"plu": "3626",
"image": "https://server-ifps.accurateig.com/assets/commodities/3626-meyer-lemons_1460404763.jpg"
},
{
"name": "Cebollines / Cebollas",
"plu": "4068",
"image": "https://server-ifps.accurateig.com/assets/commodities/4068-onions-green-2_1625063600.jpg"
},
{
"name": "Ajo",
"plu": "4608",
"image": "https://server-ifps.accurateig.com/assets/commodities/4608-garlic-regular_1637184640.jpg"
},
{
"name": "Zanahorias",
"plu": "4560",
"image": "https://server-ifps.accurateig.com/assets/commodities/4560-carrots-baby_1625673556.jpg"
},
{
"name": "Plátanos",
"plu": "4235",
"image": "https://server-ifps.accurateig.com/assets/commodities/4235-plantains-01_1625076376.jpg"
},
{
"name": "Manzanas",
"plu": "4099",
"image": "https://server-ifps.accurateig.com/assets/commodities/apples-akane_1629314651.png"
},
{
"name": "Naranjas",
"plu": "4381",
"image": "https://server-ifps.accurateig.com/assets/commodities/4381-oranges-blood-01_1625082045.jpg"
},
{
"name": "Choclo",
"plu": "3087",
"image": "https://server-ifps.accurateig.com/assets/commodities/3087-corn-04_1614633780.jpg"
},
{
"name": "Zapallo",
"plu": "4734",
"image": "https://server-ifps.accurateig.com/assets/commodities/4734-mini-pumpkin_1633964765.jpg"
},
{
"name": "Zapallo italiano",
"plu": "4750",
"image": "https://server-ifps.accurateig.com/assets/commodities/4750-squash-acorn-01_1625751871.jpg"
},
{
"name": "Repollo",
"plu": "4069",
"image": "https://server-ifps.accurateig.com/assets/commodities/4069-green-cabbage_1633958066.jpg"
},
{
"name": "Betarragas",
"plu": "4537",
"image": "https://server-ifps.accurateig.com/assets/commodities/4537-baby-golden-beets_1635173500.jpg"
},
{
"name": "Porotos verdes",
"plu": "4527",
"image": "https://server-ifps.accurateig.com/assets/commodities/4527-beans-chinese-long-07_1625671743.jpg"
},
{
"name": "Mandarinas",
"plu": "3524",
"image": "https://server-ifps.accurateig.com/assets/commodities/noble-juicycrunch-productisolated-900x900-rgb-copy_1627662136.png"
},
{
"name": "Uvas",
"plu": "3491",
"image": "https://server-ifps.accurateig.com/assets/commodities/arra-15-grape_1518122851.JPG"
},
{
"name": "Duraznos",
"plu": "3113",
"image": "https://server-ifps.accurateig.com/assets/commodities/3113-peaches-donut-04_1614707155.jpg"
},
{
"name": "Cerezas",
"plu": "3549",
"image": "https://server-ifps.accurateig.com/assets/commodities/screenshot-2023-05-02-100428_1683036305.png"
},
{
"name": "Peras",
"plu": "3317",
"image": "https://server-ifps.accurateig.com/assets/commodities/3317-angelys-pear_1460402454.jpg"
},
{
"name": "Ciruelas",
"plu": "4435",
"image": "https://server-ifps.accurateig.com/assets/commodities/4435-plums-greengage-01_1625667846.jpg"
},
{
"name": "Kiwi",
"plu": "3279",
"image": "https://server-ifps.accurateig.com/assets/commodities/3279-kiwi-gold-03_1614718637.jpg"
},
{
"name": "Piña",
"plu": "4430",
"image": "https://server-ifps.accurateig.com/assets/commodities/4430-pineapple-05_1625667649.jpg"
},
{
"name": "Puerros",
"plu": "4629",
"image": "https://server-ifps.accurateig.com/assets/commodities/4629-leeks-02_1625680225.jpg"
},
{
"name": "Alcachofas",
"plu": "4519",
"image": "https://server-ifps.accurateig.com/assets/commodities/4519-artichokes-baby-02_1625671366.jpg"
},
{
"name": "Espárragos",
"plu": "4521",
"image": "https://server-ifps.accurateig.com/assets/commodities/4521-asparagus-01_1625671446.jpg"
},
{
"name": "Berenjena",
"plu": "4599",
"image": "https://server-ifps.accurateig.com/assets/commodities/4599-baby-eggplant-aubergine_1633372314.jpg"
},
{
"name": "Durazno Nectarin",
"plu": "3437",
"image": "https://server-ifps.accurateig.com/assets/commodities/yellow-fleshed-flat-nectarine_1629140965.jpg"
},
{
"name": "Damascos",
"plu": "3044",
"image": "https://server-ifps.accurateig.com/assets/commodities/3044-apricots-black-velvet-03_1614619576.jpg"
},
{
"name": "Membrillo",
"plu": "4447",
"image": "https://server-ifps.accurateig.com/assets/commodities/4447-quince-1_1625668926.jpg"
},
{
"name": "Champiñones",
"plu": "4647",
"image": "https://server-ifps.accurateig.com/assets/commodities/4647-mushrooms-chanterelles-1_1625681503.jpg"
},
{
"name": "Castañas",
"plu": "4927",
"image": "https://server-ifps.accurateig.com/assets/commodities/4927-chestnuts-italian-02_1625756943.jpg"
}
]

View File

@@ -0,0 +1,116 @@
import os
import json
import requests
import barcode
import urllib3
import re
from barcode.writer import ImageWriter
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# --- CONFIGURATION ---
JSON_FILE = os.path.join(os.getcwd(), 'frutas2.json')
OUTPUT_DIR = os.path.join(os.getcwd(), 'keychain_cards')
IMG_CACHE_DIR = os.path.join(os.getcwd(), 'image_cache')
os.makedirs(OUTPUT_DIR, exist_ok=True)
os.makedirs(IMG_CACHE_DIR, exist_ok=True)
def clean_filename(name):
"""Prevents Windows path errors by stripping illegal characters."""
return re.sub(r'[\\/*?:"<>|]', "_", name)
def get_ean_from_plu(plu):
"""Standard 4-digit PLU to EAN-13 padding."""
return f"000000{str(plu).zfill(4)}00"
def get_cached_image(url, plu):
"""Checks local cache before downloading."""
cache_path = os.path.join(IMG_CACHE_DIR, f"{plu}.jpg")
if os.path.exists(cache_path):
return cache_path
try:
headers = {'User-Agent': 'Mozilla/5.0'}
res = requests.get(url, headers=headers, timeout=10, verify=False)
if res.status_code == 200:
with open(cache_path, 'wb') as f:
f.write(res.content)
return cache_path
except Exception as e:
print(f"❌ Error downloading {plu}: {e}")
return None
def generate_card(item):
name = item['name']
plu = item['plu']
img_url = item['image']
# Use original English name for filename and display
safe_name = clean_filename(name).replace(' ', '_')
final_path = os.path.join(OUTPUT_DIR, f"PLU_{plu}_{safe_name}.png")
# 1. Skip if already done
if os.path.exists(final_path):
return
# 2. Local Image Fetch
local_img_path = get_cached_image(img_url, plu)
# 3. Canvas Setup
card = Image.new('RGB', (300, 450), color='white')
draw = ImageDraw.Draw(card)
# Thicker frame as requested (width=3)
draw.rectangle([0, 0, 299, 449], outline="black", width=3)
if local_img_path:
try:
img = Image.open(local_img_path).convert("RGB")
w, h = img.size
size = min(w, h)
img = img.crop(((w-size)//2, (h-size)//2, (w+size)//2, (h+size)//2))
img = img.resize((200, 200), Image.Resampling.LANCZOS)
card.paste(img, (50, 40))
except:
draw.text((150, 140), "[IMG ERROR]", anchor="mm", fill="red")
else:
draw.text((150, 140), "[NOT FOUND]", anchor="mm", fill="red")
# 4. Text
try:
# Standard Windows font path
f_name = ImageFont.truetype("arialbd.ttf", 22)
f_plu = ImageFont.truetype("arial.ttf", 18)
except:
f_name = f_plu = ImageFont.load_default()
draw.text((150, 260), name.upper(), fill="black", font=f_name, anchor="mm")
draw.text((150, 295), f"PLU: {plu}", fill="#333333", font=f_plu, anchor="mm")
# 5. Barcode
EAN = barcode.get_barcode_class('ean13')
ean = EAN(get_ean_from_plu(plu), writer=ImageWriter())
tmp = f"tmp_{plu}"
ean.save(tmp, options={'module_height': 12.0, 'font_size': 10, 'text_distance': 4})
if os.path.exists(f"{tmp}.png"):
b_img = Image.open(f"{tmp}.png")
b_img = b_img.resize((280, 120))
card.paste(b_img, (10, 320))
os.remove(f"{tmp}.png")
card.save(final_path)
print(f"✅ Card created: {name} ({plu})")
if __name__ == "__main__":
if not os.path.exists(JSON_FILE):
print(f"❌ Missing {JSON_FILE}")
else:
with open(JSON_FILE, 'r', encoding='utf-8') as f:
data = json.load(f)
print(f"Processing {len(data)} cards...")
for entry in data:
generate_card(entry)
print("\nAll done. Try not to lose your keys.")

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 819 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 651 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 814 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 906 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 994 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

Some files were not shown because too many files have changed in this diff Show More