Compare commits
87 Commits
win_im_cre
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
9c6c5524a8 | ||
|
482d53af93 | ||
|
891f7fecf2 | ||
|
0f0b29e03e | ||
|
0280863e74 | ||
|
d3b74c80e0 | ||
|
d1cf3552bf | ||
|
9b260c1975 | ||
|
58a4545a40 | ||
|
4dc9452156 | ||
|
6abc4c4691 | ||
|
5f1e1c88d7 | ||
|
2801b14b05 | ||
|
3b73faa794 | ||
|
83b43cdd5b | ||
|
276bcb7ff9 | ||
|
87938079b3 | ||
|
cc3bc15ac8 | ||
|
77f0a2a19d | ||
|
1b5a86b0a2 | ||
|
00c58c925d | ||
|
abc2025032 | ||
|
38e68ce92d | ||
|
161e8cb728 | ||
|
a561b1a08b | ||
|
4373dab299 | ||
|
cb4b642a70 | ||
|
4f6c2190d6 | ||
|
41f70c6cf2 | ||
|
c3dad58e41 | ||
|
edcaf98b42 | ||
|
3bf33f9d30 | ||
|
05d983dae3 | ||
|
19eadd9d81 | ||
|
1faf6301b6 | ||
|
60852d1ad0 | ||
|
955f383031 | ||
|
d9a47dfd55 | ||
|
41756716e7 | ||
|
70207f351f | ||
|
35426ab931 | ||
|
910dd6e62f | ||
|
56e5458814 | ||
|
d57189b086 | ||
|
8b30ab0ec8 | ||
|
6203bf186f | ||
|
b14283af8d | ||
|
5d6923aaf6 | ||
|
0263b7bc6f | ||
|
2c81b71556 | ||
|
13afd1dfee | ||
|
56fea85607 | ||
|
60ca1f4bb3 | ||
|
e8f5b8dba9 | ||
|
44a6990a4c | ||
|
b0db41c11a | ||
|
fada354c74 | ||
|
faecbf0fc6 | ||
|
fac9ac8dcc | ||
|
83ef33480a | ||
|
ee2e6e96e4 | ||
|
9145838701 | ||
|
3aff64a933 | ||
|
afbfa02566 | ||
|
1b87107d3c | ||
|
1b415d50c5 | ||
|
4f5e14e131 | ||
|
380930e8e7 | ||
|
df06ca94a3 | ||
|
f5ed42c5e6 | ||
|
74ad0ad523 | ||
|
16930a2770 | ||
|
3ad7d6f6fc | ||
|
855e80f6e5 | ||
|
f87c84db30 | ||
|
10dab6a7f5 | ||
|
864a07cd89 | ||
|
67762fda4a | ||
|
c8c6b2f405 | ||
|
ae874feb75 | ||
|
d3b4728c3c | ||
|
99ec1d099d | ||
|
9a83760295 | ||
|
e0995302eb | ||
|
33c335b001 | ||
|
35574ef69f | ||
|
3b72176d9c |
40
README.md
40
README.md
@ -9,21 +9,39 @@ Super simple, super stupid.
|
|||||||
## --------------------------------
|
## --------------------------------
|
||||||
## >>>Рисование<<<:
|
## >>>Рисование<<<:
|
||||||
## Уровень: ламер
|
## Уровень: ламер
|
||||||
1. Скачать im_creator.py
|
1. Скачать im_convert.py
|
||||||
2. Запустить через `python3 im_creator.py`
|
2. Запустить через `python3 im_creator.py`
|
||||||
3. Нарисовать что-то.
|
3. Загрузить/нарисовать изображение, файл - image.png где и скрипт. (желательно не больше 128 на 128 пикселей)
|
||||||
4. Нажать кнопку "Upload" для загрузки рисунка на сервер.
|
4. Задать смещение по координатам X и Y.
|
||||||
5. Ждать надписи в консоли "DONE"
|
5. Проверить результат - должно показать конвертированное изображение.
|
||||||
|
6. Включить/выключить оптимизацию. ( (Y/N), оно убирает фоновый цвет, чем уменьшеает время на отрисовку)
|
||||||
|
7. Загрузить изображение. (Y)
|
||||||
|
|
||||||
## Уровень: овнокодер
|
## Уровень: овнокодер (типо документация)
|
||||||
Вы можете написать свой скрипт на основе post.py или...
|
Вы можете написать свой скрипт на основе post.py (почти ничего нету) или...
|
||||||
1. Скачать bot.py
|
1. Скачать bot.py
|
||||||
2. Запрогроммировать свои инструкции для бота:
|
2. Запрогроммировать свои инструкции для бота:
|
||||||
#### draw([0,1], [0,2]) - Функция для рисования, использует массив списков.
|
### Функция gcolor(x, y)
|
||||||
( Поставить точки в координатах [0,1] и [0,2] формата [x,y] )
|
- Принимает на вход два параметра: x и y - координаты пикселя на сайте.
|
||||||
#### linex(y, x1, x2) - Функция для создания массива линии по координате Х
|
- Возвращает цвет пикселя, например: "white" (белый).
|
||||||
( Y остаётся таким же, массив идёт из x1 в x2 )
|
|
||||||
#### liney(x, y1, y2) - Аналогично.
|
### Функция draw(cords, color = "black")
|
||||||
|
- Принимает на вход список cords - список координат для точек.
|
||||||
|
- Опциональный параметр color, для изменения цвета. ( полезно только для списков из fill()/linex()/liney() )
|
||||||
|
- Возвращает строку "DONE!" после отрисовки.
|
||||||
|
|
||||||
|
### Функция linex(y, x1, x2)
|
||||||
|
- Принимает на вход три параметра: y - координата Y, x1 - первая координата X, x2 - вторая кордината X.
|
||||||
|
- Создаёт массив координат: линия из [x1, y] в [x2, y].
|
||||||
|
- !! x2 должен быть больше x1 !!
|
||||||
|
- Возвращает массив координат, можно передать в draw()
|
||||||
|
|
||||||
|
### Функция liney(x, y1, y2)
|
||||||
|
- Аналогично, только по Y.
|
||||||
|
|
||||||
|
### Функция fill(xy1, xy2)
|
||||||
|
- Принимает на вход два параметра: xy1 и xy2 - координаты двух точек прямоугольника для заливки.
|
||||||
|
- Возвращает массив координат, можно передать в draw()
|
||||||
## --------------------------------
|
## --------------------------------
|
||||||
|
|
||||||
## Установка своего сервера:
|
## Установка своего сервера:
|
||||||
|
119
bot.py
119
bot.py
@ -1,58 +1,87 @@
|
|||||||
import requests
|
import requests
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
# Progress-bar
|
||||||
|
from tqdm import tqdm
|
||||||
|
# Work with list-like objects
|
||||||
|
from listwork import *
|
||||||
|
|
||||||
def draw(cords):
|
# Easy debug
|
||||||
for i in range(len(cords)):
|
from icecream import ic
|
||||||
sleep(0.2)
|
ic.disable() # Disable debug
|
||||||
try:
|
|
||||||
payload = {'x': cords[i][1], 'y': cords[i][0], 'color': cords[i][2]}
|
|
||||||
except:
|
|
||||||
payload = {'x': cords[i][1], 'y': cords[i][0], 'color': "blue" }
|
|
||||||
|
|
||||||
response = requests.post('http://pb.dmcraft.online', data=payload)
|
global server
|
||||||
print(response)
|
#server = 'http://127.0.0.1:3333'
|
||||||
|
server = 'http://pb.gulyaipole.fun'
|
||||||
|
|
||||||
while str(response) != "<Response [200]>":
|
# fill(0,0, 10,10, [0,0,0])
|
||||||
response = requests.post('http://pb.dmcraft.online', data=payload)
|
def fill(x1,y1, x2,y2, color):
|
||||||
print("Retrying...")
|
pxls = []
|
||||||
print(response)
|
r = color[0] ; g = color[1] ; b = color[2]
|
||||||
print("DONE!")
|
for x in range(x1, x2+1):
|
||||||
|
for y in range(y1, y2+1):
|
||||||
|
pxls.append([x, y, r, g, b])
|
||||||
|
return pxls
|
||||||
|
|
||||||
def linex(y, x1, x2):
|
# draw( fill(...), limit=500, token="fdsfs" )
|
||||||
res = []
|
def draw(pxls, limit=300, token="None"):
|
||||||
for i in range(x1, x2+1):
|
global server
|
||||||
res.append( [i,y] )
|
ic(pxls)
|
||||||
return res
|
|
||||||
|
|
||||||
def liney(x, y1, y2):
|
push = [] # Push %limit% items
|
||||||
res = []
|
while len(pxls) > limit:
|
||||||
for i in range(y1, y2+1):
|
packs = [] # Merge elements to %limit% size list
|
||||||
res.append( [x,i] )
|
for i in range(limit):
|
||||||
return res
|
# Take first element
|
||||||
|
packs.append(pxls[0])
|
||||||
|
pxls.pop(0)
|
||||||
|
push.append({"main": pack(packs), "token": token})
|
||||||
|
push.append({"main": pack(pxls), "token": token}) # Pack last
|
||||||
|
|
||||||
|
ic(push)
|
||||||
|
for i in tqdm(push):
|
||||||
|
response = requests.post(server, i)
|
||||||
|
while not response.status_code == 200:
|
||||||
|
print("Error, retrying...")
|
||||||
|
response = requests.post(server, i)
|
||||||
|
sleep(0.1)
|
||||||
|
|
||||||
|
# cfill(0,0, 10,10) // Limit - 34x34
|
||||||
|
def cfill(x1,y1, x2,y2):
|
||||||
|
pxls = []
|
||||||
|
for x in range(x1, x2+1):
|
||||||
|
for y in range(y1, y2+1):
|
||||||
|
pxls.append([x, y])
|
||||||
|
packed = pack(pxls)
|
||||||
|
return packed
|
||||||
|
|
||||||
|
# ccheck( packed([[0,0]]) ) or ccheck(cfill(...))
|
||||||
|
def ccheck(packed):
|
||||||
|
global server
|
||||||
|
response = requests.get(f'{server}/get_color={packed}')
|
||||||
|
ic(response.text)
|
||||||
|
out = unpack(response.text)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
l = [[65, 86, 'red'], [66, 87, 'red'], [66, 86, 'red'], [66, 85, 'red'], [67, 86, 'red'], [89, 97, 'red'], [90, 98, 'red'], [90, 97, 'red'], [90, 96, 'red'], [91, 97, 'red'], [95, 77, 'black'], [96, 78, 'black'], [96, 77, 'black'], [96, 76, 'black'], [97, 77, 'black'], [107, 108, 'blue'], [108, 109, 'blue'], [108, 108, 'blue'], [108, 107, 'blue'], [109, 108, 'blue']]
|
|
||||||
|
|
||||||
draw(l)
|
### EXAMPLE
|
||||||
|
# Draw random square 100x100 on 0,0
|
||||||
|
from random import randint as ri
|
||||||
|
draw( fill(0,0, 100,100, [ri(0,255),ri(0,255),ri(0,255)]) )
|
||||||
|
|
||||||
|
# Check square 34x34 on 0,0
|
||||||
|
print(ccheck(cfill(0,0, 34,34)))
|
||||||
|
|
||||||
#draw( liney(300, 300, 500) )
|
# Use extras, draw 1/2 random square 100x100 on 0,0
|
||||||
#draw(linex(500, 300, 500))
|
from bot_extras import *
|
||||||
|
draw(pas2( rand(0,0, 100,100) ))
|
||||||
|
|
||||||
'''
|
# Draw image (flipped (BUG) )
|
||||||
xs = 180
|
from im_convert import *
|
||||||
ys = 180
|
image = convert("example.png", [10,0])
|
||||||
#S
|
from remove_back import *
|
||||||
cords = [ [3+xs,0+ys],[2+xs,0+ys],[1+xs,0+ys],[1+xs,-1+ys],[1+xs,-2+ys],[2+xs,-2+ys],[3+xs,-2+ys],[3+xs,-3+ys],[3+xs,-4+ys],[2+xs,-4+ys],[1+xs,-4+ys] ]
|
draw( optimize(image, [255,255,255]) ) # Remove white background and draw
|
||||||
draw(cords)
|
|
||||||
#A
|
# Draw with premium-token, limit 600 (default token)
|
||||||
cords = [ [5+xs,-4+ys],[5+xs,-3+ys],[5+xs,-2+ys],[5+xs,-1+ys],[5+xs,0+ys],[6+xs,0+ys],[7+xs,0+ys],[8+xs,0+ys],[8+xs,-4+ys],[8+xs,-3+ys],[8+xs,-2+ys],[8+xs,-1+ys],[8+xs,0+ys],[5+xs,-2+ys],[6+xs,-2+ys],[7+xs,-2+ys],[8+xs,-2+ys], ]
|
# Token is fake, >ERROR<
|
||||||
draw(cords)
|
draw( fill(758,0, 1123,198, [255,255,255]), limit=600, token="3744138bd462cd8180e4w3534rfdsw4rwert" )
|
||||||
#N
|
|
||||||
cords = [ [10+xs,-4+ys],[10+xs,-3+ys],[10+xs,-2+ys],[10+xs,-1+ys],[10+xs,0+ys],[11+xs,-1+ys],[12+xs,-2+ys],[13+xs,-3+ys],[14+xs,-4+ys],[15+xs,-4+ys],[15+xs,-3+ys],[15+xs,-2+ys],[15+xs,-1+ys],[15+xs,0+ys], ]
|
|
||||||
draw(cords)
|
|
||||||
#S
|
|
||||||
xs = xs + 16
|
|
||||||
cords = [ [3+xs,0+ys],[2+xs,0+ys],[1+xs,0+ys],[1+xs,-1+ys],[1+xs,-2+ys],[2+xs,-2+ys],[3+xs,-2+ys],[3+xs,-3+ys],[3+xs,-4+ys],[2+xs,-4+ys],[1+xs,-4+ys] ]
|
|
||||||
draw(cords)
|
|
||||||
'''
|
|
||||||
|
23
bot_extras.py
Normal file
23
bot_extras.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from listwork import *
|
||||||
|
from random import randint as ri
|
||||||
|
|
||||||
|
# pas2( fill(...) ) -> 1/2
|
||||||
|
def pas2(pxls):
|
||||||
|
new_pxls = []
|
||||||
|
|
||||||
|
pas = False
|
||||||
|
for i in pxls:
|
||||||
|
if not pas:
|
||||||
|
new_pxls.append(i)
|
||||||
|
pas = True
|
||||||
|
else:
|
||||||
|
pas = False
|
||||||
|
return new_pxls
|
||||||
|
|
||||||
|
# rand(x1,y1, x2,y2) -> draw() or pas2()
|
||||||
|
def rand(x1,y1, x2,y2):
|
||||||
|
pxls = []
|
||||||
|
for x in range(x1, x2 +1):
|
||||||
|
for y in range(y1, y2 +1):
|
||||||
|
pxls.append([x,y, ri(0,255), ri(0,255), ri(0,255)])
|
||||||
|
return pxls
|
BIN
example.png
Normal file
BIN
example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.9 KiB |
42
gpt_blob.py
Normal file
42
gpt_blob.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
def start_drag(event):
|
||||||
|
global current_coords
|
||||||
|
global dragged_item
|
||||||
|
dragged_item = label
|
||||||
|
current_coords = label.winfo_pointerx(), label.winfo_pointery()
|
||||||
|
|
||||||
|
def stop_drag(event):
|
||||||
|
dragged_item = None
|
||||||
|
|
||||||
|
def drag(event):
|
||||||
|
global current_coords
|
||||||
|
xc, yc = label.winfo_pointerx(), label.winfo_pointery()
|
||||||
|
dx, dy = xc - current_coords[0], yc - current_coords[1]
|
||||||
|
current_coords = xc, yc
|
||||||
|
label.place(x=label.winfo_x() + dx, y=label.winfo_y() + dy)
|
||||||
|
|
||||||
|
def nn(root,im):
|
||||||
|
global label
|
||||||
|
|
||||||
|
image = tk.PhotoImage(file=im) # Use self.image
|
||||||
|
label = tk.Label(root, image=image)
|
||||||
|
label.image = image # Keep a reference to the image
|
||||||
|
label.pack()
|
||||||
|
|
||||||
|
dragged_item = None
|
||||||
|
current_coords = 0, 0
|
||||||
|
|
||||||
|
label.bind('<ButtonPress-1>', start_drag)
|
||||||
|
label.bind('<ButtonRelease-1>', stop_drag)
|
||||||
|
label.bind('<B1-Motion>', drag)
|
||||||
|
# globals().update(locals())
|
||||||
|
|
||||||
|
while True:
|
||||||
|
tk.Misc.lift(label)
|
||||||
|
sleep(0.05)
|
||||||
|
|
||||||
|
print("Image cords: ", label.winfo_x(), 720 - label.winfo_y() - image.height())
|
||||||
|
#x1, y1 = image.coords(image)
|
||||||
|
# print(f'Image cords: {}')
|
52
im_convert.py
Normal file
52
im_convert.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
from PIL import Image, ImageOps
|
||||||
|
|
||||||
|
# [[0,0, rgb1],... [1,1, rgb2]] -> [[1,1, rgb1],...[0,0, rgb2]]
|
||||||
|
def flip(cords):
|
||||||
|
fliped = []
|
||||||
|
flips = len(cords)//2
|
||||||
|
|
||||||
|
# El from start and el from end
|
||||||
|
fl0 = 0 ; fl1 = len(cords)-1
|
||||||
|
|
||||||
|
for i in range(flips):
|
||||||
|
# Copy element and change cords to cords of end element
|
||||||
|
new_st = list(cords[fl0])
|
||||||
|
new_st[0] = cords[fl1][0]
|
||||||
|
new_st[1] = cords[fl1][1]
|
||||||
|
fliped.append(new_st)
|
||||||
|
|
||||||
|
# Copy and change cords to cords of start element
|
||||||
|
new_end = list(cords[fl1])
|
||||||
|
new_end[0] = cords[fl0][0]
|
||||||
|
new_end[1] = cords[fl0][1]
|
||||||
|
fliped.append(new_end)
|
||||||
|
|
||||||
|
fl0 += 1 ; fl1 -= 1
|
||||||
|
|
||||||
|
return fliped
|
||||||
|
|
||||||
|
# convert("example.png") // png/jpg/gif
|
||||||
|
def convert(filename, move = [0,0]):
|
||||||
|
im = Image.open(filename).convert('RGB')
|
||||||
|
# Fix mirror
|
||||||
|
im = ImageOps.mirror(im)
|
||||||
|
pxls=im.load()
|
||||||
|
w=im.size[0]
|
||||||
|
h=im.size[1]
|
||||||
|
|
||||||
|
ll = []
|
||||||
|
for x in range(w):
|
||||||
|
for y in range(h):
|
||||||
|
# [x,y, [r, g, b]]
|
||||||
|
rgb = pxls[x,y]
|
||||||
|
ll.append( [x,y, rgb[0], rgb[1], rgb[2] ] )
|
||||||
|
|
||||||
|
# Fix flip
|
||||||
|
fliped = flip(ll)
|
||||||
|
|
||||||
|
# Move [x,y] + move
|
||||||
|
moved = []
|
||||||
|
for i in fliped:
|
||||||
|
moved.append([i[0] + move[0], i[1] + move[1], i[2],i[3],i[4]])
|
||||||
|
|
||||||
|
return moved
|
115
im_create.py
115
im_create.py
@ -1,115 +0,0 @@
|
|||||||
from tkinter import *
|
|
||||||
|
|
||||||
####DRAW BLOCK
|
|
||||||
import requests
|
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
def draw(cords):
|
|
||||||
for i in range(len(cords)):
|
|
||||||
sleep(0.2)
|
|
||||||
try:
|
|
||||||
payload = {'x': cords[i][1], 'y': cords[i][0], 'color': cords[i][2]}
|
|
||||||
except:
|
|
||||||
payload = {'x': cords[i][1], 'y': cords[i][0], 'color': "b" }
|
|
||||||
|
|
||||||
response = requests.post('http://pb.dmcraft.online', data=payload)
|
|
||||||
print(response)
|
|
||||||
|
|
||||||
while str(response) != "<Response [200]>":
|
|
||||||
response = requests.post('http://pb.dmcraft.online', data=payload)
|
|
||||||
print("Retrying...")
|
|
||||||
print(response)
|
|
||||||
print("!!!DONE!!!")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PixelArt:
|
|
||||||
|
|
||||||
def __init__(self, master):
|
|
||||||
self.master = master
|
|
||||||
self.master.title("Pixel Art")
|
|
||||||
self.canvas = Canvas(self.master, width=128*12, height=128*12, bg="white")
|
|
||||||
self.canvas.pack(side=LEFT, padx=5, pady=5)
|
|
||||||
self.colors = ["red", "green", "blue", "white","black"]
|
|
||||||
self.current_color = "red"
|
|
||||||
self.button_frame = Frame(self.master)
|
|
||||||
|
|
||||||
self.button_frame.pack(side=LEFT, padx=5, pady=5)
|
|
||||||
self.export_button = Button(self.button_frame, text="Export", command=self.export_image)
|
|
||||||
self.export_button.pack(side=TOP, padx=5, pady=5)
|
|
||||||
|
|
||||||
self.button_frame.pack(side=LEFT, padx=5, pady=5)
|
|
||||||
self.export_button = Button(self.button_frame, text="Clean", command=self.clean_image)
|
|
||||||
self.export_button.pack(side=TOP, padx=5, pady=5)
|
|
||||||
|
|
||||||
self.button_frame.pack(side=LEFT, padx=5, pady=5)
|
|
||||||
self.export_button = Button(self.button_frame, text="Upload", command=self.upload_image)
|
|
||||||
self.export_button.pack(side=TOP, padx=5, pady=5)
|
|
||||||
|
|
||||||
self.color_buttons = []
|
|
||||||
for color in self.colors:
|
|
||||||
button = Button(self.button_frame, bg=color, width=3, height=1, command=lambda c=color: self.set_color(c))
|
|
||||||
button.pack(side=TOP, padx=5, pady=5)
|
|
||||||
self.color_buttons.append(button)
|
|
||||||
for i in range(129):
|
|
||||||
self.canvas.create_line(i*12, 0, i*12, 128*12, fill="white")
|
|
||||||
self.canvas.create_line(0, i*12, 128*12, i*12, fill="white")
|
|
||||||
self.canvas.bind("<Button-1>", self.draw_pixel)
|
|
||||||
|
|
||||||
def draw_pixel(self, event):
|
|
||||||
x = int(event.x / 12)
|
|
||||||
y = int(event.y / 12)
|
|
||||||
self.canvas.create_rectangle(x*12, y*12, x*12 + 12, y*12 + 12, fill=self.current_color)
|
|
||||||
|
|
||||||
def set_color(self, color):
|
|
||||||
self.current_color = color
|
|
||||||
|
|
||||||
def clean_image(self):
|
|
||||||
items = self.canvas.find_all()
|
|
||||||
for item in items:
|
|
||||||
self.canvas.delete(item)
|
|
||||||
|
|
||||||
def upload_image(self):
|
|
||||||
pixel_data = []
|
|
||||||
for i in range(128):
|
|
||||||
for j in range(128):
|
|
||||||
color = self.canvas.itemcget(self.canvas.find_closest(i*12+6, j*12+6), "fill")
|
|
||||||
if color != "white":
|
|
||||||
match self.colors.index(color):
|
|
||||||
case 0:
|
|
||||||
color = "red"
|
|
||||||
case 1:
|
|
||||||
color = "green"
|
|
||||||
case 2:
|
|
||||||
color = "blue"
|
|
||||||
case 3:
|
|
||||||
color = "black"
|
|
||||||
pixel_data.append([i, 127-j, color])
|
|
||||||
print("!!!START UPLOAD!!!")
|
|
||||||
draw(pixel_data)
|
|
||||||
|
|
||||||
def export_image(self):
|
|
||||||
pixel_data = []
|
|
||||||
for i in range(128):
|
|
||||||
for j in range(128):
|
|
||||||
color = self.canvas.itemcget(self.canvas.find_closest(i*12+6, j*12+6), "fill")
|
|
||||||
if color != "white":
|
|
||||||
match self.colors.index(color):
|
|
||||||
case 0:
|
|
||||||
color = "red"
|
|
||||||
case 1:
|
|
||||||
color = "green"
|
|
||||||
case 2:
|
|
||||||
color = "blue"
|
|
||||||
case 3:
|
|
||||||
color = "black"
|
|
||||||
pixel_data.append([i, 127-j, color])
|
|
||||||
f = open('out.txt', 'w')
|
|
||||||
f.write(str(pixel_data))
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
root = Tk()
|
|
||||||
pixel_art = PixelArt(root)
|
|
||||||
root.mainloop()
|
|
24
listwork.py
Normal file
24
listwork.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
def unpack(string):
|
||||||
|
ll = string.split('-_')
|
||||||
|
ll.remove("") # Remove empty line
|
||||||
|
el_col = ll[0].count('-')
|
||||||
|
|
||||||
|
post_ll = []
|
||||||
|
for i in ll:
|
||||||
|
temp = i.split("-")
|
||||||
|
# Multi-add (2, 3 or 5 elements)
|
||||||
|
if el_col == 1:
|
||||||
|
post_ll.append([int(temp[0]), int(temp[1])])
|
||||||
|
elif el_col == 2:
|
||||||
|
post_ll.append([int(temp[0]), int(temp[1]), int(temp[2])])
|
||||||
|
elif el_col == 4:
|
||||||
|
post_ll.append([int(temp[0]), int(temp[1]), int(temp[2]), int(temp[3]), int(temp[4]) ])
|
||||||
|
return post_ll
|
||||||
|
|
||||||
|
def pack(ll):
|
||||||
|
string = ''
|
||||||
|
for el in ll:
|
||||||
|
for i in el:
|
||||||
|
string += str(i) + '-'
|
||||||
|
string += '_'
|
||||||
|
return string
|
90
main.py
90
main.py
@ -1,90 +0,0 @@
|
|||||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
||||||
from urllib.parse import parse_qs
|
|
||||||
from io import BytesIO
|
|
||||||
from PIL import Image
|
|
||||||
import numpy as np
|
|
||||||
import time
|
|
||||||
|
|
||||||
global LTIME
|
|
||||||
LTIME = cur_time = time.monotonic()
|
|
||||||
|
|
||||||
class RequestHandler(BaseHTTPRequestHandler):
|
|
||||||
MATRIX_SIZE = (800, 1024)
|
|
||||||
COLORS = {
|
|
||||||
'w': (255, 255, 255),
|
|
||||||
'b': (0, 0, 0),
|
|
||||||
'r': (255, 0, 0),
|
|
||||||
'g': (0, 255, 0),
|
|
||||||
}
|
|
||||||
|
|
||||||
def do_GET(self):
|
|
||||||
self.send_response(200)
|
|
||||||
self.send_header('Content-type', 'image/png')
|
|
||||||
self.end_headers()
|
|
||||||
|
|
||||||
matrix = self.get_matrix()
|
|
||||||
matrix = np.flip(matrix, axis=0)
|
|
||||||
self.send_image(matrix)
|
|
||||||
|
|
||||||
def do_POST(self):
|
|
||||||
global LTIME
|
|
||||||
cur_time = time.monotonic()
|
|
||||||
address = self.client_address[0]
|
|
||||||
print("IP: ", address)
|
|
||||||
|
|
||||||
if cur_time - LTIME <= 0.01:
|
|
||||||
self.send_error(429, 'Too Many Requests')
|
|
||||||
self.send_response(429)
|
|
||||||
return 0
|
|
||||||
else:
|
|
||||||
LTIME = time.monotonic()
|
|
||||||
|
|
||||||
content_length = int(self.headers['Content-Length'])
|
|
||||||
body = self.rfile.read(content_length)
|
|
||||||
params = parse_qs(body.decode('utf-8'))
|
|
||||||
|
|
||||||
y = int(params['y'][0])
|
|
||||||
x = int(params['x'][0])
|
|
||||||
color = params['color'][0]
|
|
||||||
|
|
||||||
matrix = self.get_matrix()
|
|
||||||
matrix[x][y] = self.COLORS[color]
|
|
||||||
|
|
||||||
self.save_matrix(matrix)
|
|
||||||
self.send_response(302)
|
|
||||||
self.send_header('Location', '/')
|
|
||||||
self.end_headers()
|
|
||||||
|
|
||||||
def get_matrix(self):
|
|
||||||
try:
|
|
||||||
with open('matrix.npy', 'rb') as f:
|
|
||||||
matrix = np.load(f)
|
|
||||||
except FileNotFoundError:
|
|
||||||
matrix = np.full(shape=(*self.MATRIX_SIZE, 3), fill_value=255, dtype=np.uint8)
|
|
||||||
self.save_matrix(matrix)
|
|
||||||
|
|
||||||
return matrix
|
|
||||||
|
|
||||||
def save_matrix(self, matrix):
|
|
||||||
with open('matrix.npy', 'wb') as f:
|
|
||||||
np.save(f, matrix)
|
|
||||||
|
|
||||||
def send_image(self, matrix):
|
|
||||||
image = Image.fromarray(matrix)
|
|
||||||
buffer = BytesIO()
|
|
||||||
image.save(buffer, format='PNG')
|
|
||||||
self.wfile.write(buffer.getvalue())
|
|
||||||
|
|
||||||
|
|
||||||
def run():
|
|
||||||
server = HTTPServer(('127.0.0.1', 3333), RequestHandler)
|
|
||||||
server.serve_forever()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
run()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
88
map.py
Normal file
88
map.py
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import urllib.request
|
||||||
|
import time
|
||||||
|
from PIL import Image, ImageTk
|
||||||
|
import io
|
||||||
|
import tkinter as tk
|
||||||
|
|
||||||
|
url = "https://pb.gulyaipole.fun/"
|
||||||
|
|
||||||
|
root = tk.Tk()
|
||||||
|
root.geometry("1280x720")
|
||||||
|
|
||||||
|
# Canvas for image
|
||||||
|
canvas = tk.Canvas(root)
|
||||||
|
canvas.pack()
|
||||||
|
|
||||||
|
# XY cords
|
||||||
|
ttext = tk.Canvas(root, width=100, height=20, bg="black")
|
||||||
|
ttext.place(x=1180, y=0)
|
||||||
|
text = ttext.create_text(50, 10, text="X: 1, Y: 1", fill="white")
|
||||||
|
|
||||||
|
# Run threads
|
||||||
|
from threading import Thread
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
def cords_up():
|
||||||
|
while True:
|
||||||
|
x = root.winfo_pointerx() - root.winfo_rootx()
|
||||||
|
y = 720 - (root.winfo_pointery() - root.winfo_rooty())
|
||||||
|
ttext.itemconfig(text, text=f"X: {x}, Y: {y}")
|
||||||
|
sleep(0.05)
|
||||||
|
|
||||||
|
cords = Thread(target=cords_up)
|
||||||
|
cords.start()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### WARN, GPT-BLOB ####
|
||||||
|
|
||||||
|
from gpt_blob import *
|
||||||
|
|
||||||
|
# Get file from args
|
||||||
|
from sys import argv
|
||||||
|
|
||||||
|
try:
|
||||||
|
im = argv[1]
|
||||||
|
n = Thread(target=nn, args=[root, im,])
|
||||||
|
n.start()
|
||||||
|
except:
|
||||||
|
print("None image")
|
||||||
|
|
||||||
|
#######################
|
||||||
|
|
||||||
|
|
||||||
|
def map_up():
|
||||||
|
global canvas_old, canvas, label
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# Prepare image for tkiner
|
||||||
|
image_file = io.BytesIO(urllib.request.urlopen(url).read())
|
||||||
|
img = Image.open(image_file)
|
||||||
|
tk_img = ImageTk.PhotoImage(img)
|
||||||
|
|
||||||
|
# Create new canvas
|
||||||
|
canvas = tk.Canvas(root, width=img.size[0], height=img.size[1])
|
||||||
|
canvas.create_image(0, 0, anchor="nw", image=tk_img)
|
||||||
|
canvas.place(x=0, y=0)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# New canvas and cords up
|
||||||
|
tk.Misc.lift(canvas)
|
||||||
|
tk.Misc.lift(ttext)
|
||||||
|
# Update
|
||||||
|
root.update()
|
||||||
|
sleep(2)
|
||||||
|
# Remove old
|
||||||
|
canvas_old.destroy()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
# New canvas now is old
|
||||||
|
canvas_old = canvas
|
||||||
|
|
||||||
|
map = Thread(target=map_up)
|
||||||
|
map.start()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
root.mainloop()
|
||||||
|
|
21
post.py
21
post.py
@ -1,6 +1,19 @@
|
|||||||
import requests
|
import requests
|
||||||
|
# Work with list-like objects
|
||||||
|
from listwork import *
|
||||||
|
|
||||||
|
server = 'http://127.0.0.1:3333'
|
||||||
|
|
||||||
|
# Draw some pixels
|
||||||
|
# [[x, y, color-1, color-2, color-3], ...]
|
||||||
|
fill = {"main": pack([[200, 100, 0, 0, 0], [15, 30, 255, 54, 43]]) }
|
||||||
|
response = requests.post(server, data=fill)
|
||||||
|
if response:
|
||||||
|
print("posted")
|
||||||
|
|
||||||
|
# Get color code of coords
|
||||||
|
# [[x,y], ...]
|
||||||
|
xys = pack([[200,100], [13,10], [50,50]])
|
||||||
|
response = requests.get(f'{server}/get_color={xys}')
|
||||||
|
print( unpack(response.text) )
|
||||||
|
|
||||||
payload = {'x': 52, 'y': 20, 'color': 'r'}
|
|
||||||
#response = requests.post('http://pb.dmcraft.online', data=payload)
|
|
||||||
response = requests.post('http://127.0.0.1:3333', data=payload)
|
|
||||||
print(response)
|
|
||||||
|
16
remove_back.py
Normal file
16
remove_back.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
def optimize(pxls, back):
|
||||||
|
old_len = len(pxls)
|
||||||
|
|
||||||
|
new_pxls = []
|
||||||
|
for i in tqdm(range(old_len)):
|
||||||
|
el = pxls[i]
|
||||||
|
now_back = [el[2], el[3], el[4]]
|
||||||
|
|
||||||
|
if now_back != back:
|
||||||
|
new_pxls.append(pxls[i])
|
||||||
|
|
||||||
|
print(f"Optimized {(old_len - len(new_pxls)) / old_len * 100 }%")
|
||||||
|
|
||||||
|
return new_pxls
|
167
server.py
Normal file
167
server.py
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||||
|
from urllib.parse import parse_qs
|
||||||
|
from io import BytesIO
|
||||||
|
from PIL import Image
|
||||||
|
import numpy as np
|
||||||
|
import time
|
||||||
|
|
||||||
|
# Easy debug
|
||||||
|
from icecream import ic
|
||||||
|
ic.disable() # Turn off
|
||||||
|
|
||||||
|
# Limit for requests
|
||||||
|
LTIME = cur_time = time.monotonic()
|
||||||
|
globals().update(locals())
|
||||||
|
|
||||||
|
# Key by value
|
||||||
|
def kbv(dict_, value):
|
||||||
|
for i in dict_:
|
||||||
|
if dict_[i] == value:
|
||||||
|
return i
|
||||||
|
|
||||||
|
# Work with list-like objects
|
||||||
|
from listwork import *
|
||||||
|
|
||||||
|
|
||||||
|
# Work with tokens
|
||||||
|
import json
|
||||||
|
global tokens
|
||||||
|
def tokens_load():
|
||||||
|
with open('tokens.json', 'r') as openfile:
|
||||||
|
return json.load(openfile)
|
||||||
|
|
||||||
|
# (Re)generate tokens
|
||||||
|
def tokens_regen():
|
||||||
|
import hashlib
|
||||||
|
from random import randint as ri
|
||||||
|
|
||||||
|
tokens = tokens_load()
|
||||||
|
tokens["admin"] = hashlib.sha256(str.encode( str(ri(2443, 6543)) + tokens["secret"] )).hexdigest()
|
||||||
|
|
||||||
|
tokens["premium"] = []
|
||||||
|
for i in range(10):
|
||||||
|
tokens["premium"].append( hashlib.sha256(str.encode( str(ri(2443, 6543)) + tokens["secret"] )).hexdigest() )
|
||||||
|
|
||||||
|
js = json.dumps(tokens, indent=2)
|
||||||
|
with open("tokens.json", "w") as outfile:
|
||||||
|
outfile.write(js)
|
||||||
|
|
||||||
|
# Uncomment to regen
|
||||||
|
#tokens_regen()
|
||||||
|
|
||||||
|
|
||||||
|
class RequestHandler(BaseHTTPRequestHandler):
|
||||||
|
MATRIX_SIZE = (720, 1280)
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
params = parse_qs(self.path[1:])
|
||||||
|
ic(params)
|
||||||
|
if 'get_color' in params:
|
||||||
|
params = params['get_color'][0]
|
||||||
|
ic(len(params))
|
||||||
|
xys = unpack(params)
|
||||||
|
ic.disable()
|
||||||
|
matrix = self.get_matrix()
|
||||||
|
colors = []
|
||||||
|
for i in xys:
|
||||||
|
ic(i)
|
||||||
|
x = i[0] ; y = i[1]
|
||||||
|
color = matrix[x][y]
|
||||||
|
ic(color)
|
||||||
|
|
||||||
|
colors.append(color)
|
||||||
|
|
||||||
|
colors = pack(colors)
|
||||||
|
ic(colors)
|
||||||
|
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-type', 'text/plain')
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(f'{colors}'.encode())
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-type', 'image/png')
|
||||||
|
self.end_headers()
|
||||||
|
matrix = self.get_matrix()
|
||||||
|
matrix = np.flip(matrix, axis=0) #Fix flip on server side
|
||||||
|
self.send_image(matrix)
|
||||||
|
|
||||||
|
def do_POST(self):
|
||||||
|
global LTIME
|
||||||
|
cur_time = time.monotonic()
|
||||||
|
|
||||||
|
if cur_time - LTIME <= 0.0001:
|
||||||
|
self.send_error(429, 'Too Many Requests')
|
||||||
|
self.send_response(429)
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
LTIME = time.monotonic()
|
||||||
|
|
||||||
|
content_length = int(self.headers['Content-Length'])
|
||||||
|
body = self.rfile.read(content_length)
|
||||||
|
params = parse_qs(body.decode('utf-8'))["main"][0]
|
||||||
|
ic(params)
|
||||||
|
|
||||||
|
# Parse token
|
||||||
|
ic( parse_qs(body.decode('utf-8')) )
|
||||||
|
token = parse_qs(body.decode('utf-8'))["token"][0]
|
||||||
|
|
||||||
|
#Set limit pixels for 1 response
|
||||||
|
ic(len(params))
|
||||||
|
if len(params) > 6700:
|
||||||
|
# Get tokens
|
||||||
|
tokens = tokens_load()
|
||||||
|
# Admin's token
|
||||||
|
if token[0] == tokens["admin"][0]:
|
||||||
|
pass
|
||||||
|
elif token[0] in tokens["premium"] and len(params) < 13400:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
matrix = self.get_matrix()
|
||||||
|
|
||||||
|
ll = unpack(params)
|
||||||
|
for i in ll:
|
||||||
|
x = i[1] ; y = i[0] #Fix (y, x) -> (x, y) on server side
|
||||||
|
matrix[x, y] = [i[2], i[3], i[4]]
|
||||||
|
|
||||||
|
self.save_matrix(matrix)
|
||||||
|
self.send_response(302)
|
||||||
|
self.send_header('Location', '/')
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
def get_matrix(self):
|
||||||
|
try:
|
||||||
|
with open('matrix.npy', 'rb') as f:
|
||||||
|
matrix = np.load(f)
|
||||||
|
except FileNotFoundError:
|
||||||
|
matrix = np.full(shape=(*self.MATRIX_SIZE, 3), fill_value=255, dtype=np.uint8)
|
||||||
|
self.save_matrix(matrix)
|
||||||
|
|
||||||
|
return matrix
|
||||||
|
|
||||||
|
def save_matrix(self, matrix):
|
||||||
|
with open('matrix.npy', 'wb') as f:
|
||||||
|
np.save(f, matrix)
|
||||||
|
|
||||||
|
def send_image(self, matrix):
|
||||||
|
image = Image.fromarray(matrix)
|
||||||
|
buffer = BytesIO()
|
||||||
|
image.save(buffer, format='PNG')
|
||||||
|
self.wfile.write(buffer.getvalue())
|
||||||
|
|
||||||
|
def run():
|
||||||
|
server = HTTPServer(('127.0.0.1', 3333), RequestHandler)
|
||||||
|
server.serve_forever()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
run()
|
||||||
|
print(1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
exit()
|
||||||
|
except:
|
||||||
|
pass
|
1
site/README.md
Normal file
1
site/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
Special thanks to Holinim.
|
37
site/index.html
Normal file
37
site/index.html
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>PixelBoard</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500&family=Nunito:wght@300&display=swap" rel="stylesheet">
|
||||||
|
<script>
|
||||||
|
setInterval(function() {
|
||||||
|
var image = document.getElementById('PBImage');
|
||||||
|
image.src = 'http://pb.gulyaipole.fun/' + new Date().getTime();
|
||||||
|
}, 2000);
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body bgcolor="#DAA06D"> <!--Old color - #1c5ca6-->
|
||||||
|
<button onclick="window.location.href='live_black.html';" style='background-color:#7e4a12; border-radius: 1000px'>
|
||||||
|
<img src="https://cdn.icon-icons.com/icons2/1674/PNG/32/moon_111148.png">
|
||||||
|
</button>
|
||||||
|
<p align = "center"><b><font face="Montserrat" size='5' width="500">Пиксельная доска</font></b></p>
|
||||||
|
<p align = "center">
|
||||||
|
<img id="PBImage" src="http://pb.gulyaipole.fun:3333" onclick="window.location.href='https://pb.gulyaipole.fun:3333'" height=640 style="border: 8px solid #dbac83">
|
||||||
|
<br>
|
||||||
|
<button onclick="window.location.href='https://gitea.gulyaipole.fun/justuser/pxl_oboard';" style="background-color: #c5792d; border-radius: 1000px">
|
||||||
|
<font face="Montserrat" width="400">Репозиторий проекта</font>
|
||||||
|
</button>
|
||||||
|
<button onclick="window.location.href='https://docs.google.com/document/d/1hEccpHxwDQrpTW7RMmf3lqYtJIDh1Fwb';" style="background-color: #c5792d; border-radius: 1000px">
|
||||||
|
<font face="Montserrat" width="400">Как рисовать на доске?</font>
|
||||||
|
</button>
|
||||||
|
<button onclick="window.location.href='https://t.me/pxl_oboard';" style="background-color: #c5792d; border-radius: 1000px">
|
||||||
|
<font face="Montserrat" width="400">Telegram проекта</font>
|
||||||
|
</button>
|
||||||
|
<br><br>
|
||||||
|
<b><font face="Montserrat" width="300">Правила проекта:</font></b>
|
||||||
|
<font face="Nunito"><br>1. Уважать других - не перекрывать/закрашивать чужие рисунки<br>2. Рисунки не должны представлять из себя 18+ контент или пропаганду LGBT.<br>3. Рисунки не должны нарушать законы Российской Федерации.</font>
|
||||||
|
</body>
|
||||||
|
</html>
|
37
site/live_black.html
Normal file
37
site/live_black.html
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>PixelBoard</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500&family=Nunito:wght@300&display=swap" rel="stylesheet">
|
||||||
|
<script>
|
||||||
|
setInterval(function() {
|
||||||
|
var image = document.getElementById('PBImage');
|
||||||
|
image.src = 'http://pb.gulyaipole.fun/' + new Date().getTime();
|
||||||
|
}, 2000);
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body bgcolor="#06111f">
|
||||||
|
<button onclick="window.location.href='index.html';" style='background-color:#0484da; border-radius: 1000px'>
|
||||||
|
<img src="https://cdn.icon-icons.com/icons2/1325/PNG/32/fun4x_86984.png">
|
||||||
|
</button>
|
||||||
|
<p align = "center"><b><font face="Montserrat" size='5' width="500" color='white'>Пиксельная доска</font></b></p>
|
||||||
|
<p align = "center">
|
||||||
|
<img id="PBImage" src="http://pb.gulyaipole.fun:3333" onclick="window.location.href='https://pb.gulyaipole.fun:3333'" height=640 style="border: 8px solid #101655">
|
||||||
|
<br>
|
||||||
|
<button onclick="window.location.href='https://gitea.gulyaipole.fun/justuser/pxl_oboard';" style="background-color: #112f4d; border-radius: 1000px">
|
||||||
|
<font face="Montserrat" color='white' width="400">Репозиторий проекта</font>
|
||||||
|
</button>
|
||||||
|
<button onclick="window.location.href='https://docs.google.com/document/d/1hEccpHxwDQrpTW7RMmf3lqYtJIDh1Fwb';" style="background-color: #112f4d; border-radius: 1000px">
|
||||||
|
<font face="Montserrat" color='white' width="400">Как рисовать на доске?</font>
|
||||||
|
</button>
|
||||||
|
<button onclick="window.location.href='https://t.me/pxl_oboard';" style="background-color: #112f4d; border-radius: 1000px">
|
||||||
|
<font face="Montserrat" color='white' width="400">Telegram проекта</font>
|
||||||
|
</button>
|
||||||
|
<br><br>
|
||||||
|
<b><font face="Montserrat" color='white' width="300">Правила проекта:</font></b>
|
||||||
|
<font face="Nunito" color='white'><br>1. Уважать других - не перекрывать/закрашивать чужие рисунки<br>2. Рисунки не должны представлять из себя 18+ контент или пропаганду LGBT.<br>3. Рисунки не должны нарушать законы Российской Федерации.</font>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user