That ought to do.

This commit is contained in:
Kumi 2020-10-10 21:32:57 +02:00
parent ff97a4845b
commit b2e760053f
9 changed files with 95 additions and 30 deletions

View file

@ -5,4 +5,6 @@
This application requires Python3 to be installed with all the packages listed in `requirements.txt`, as well as the following software: This application requires Python3 to be installed with all the packages listed in `requirements.txt`, as well as the following software:
* Perl and the erect2cubic package * Perl and the erect2cubic package
* Hugin (incl. Nona) * Hugin (incl. Nona)
* Java and zxing
* PythonMagick

View file

@ -1,15 +1,17 @@
import tempfile import tempfile
import subprocess import subprocess
import PIL.Image import PythonMagick
def convert(infile): def convert(infile, extension):
pto = tempfile.NamedTemporaryFile() pto = tempfile.NamedTemporaryFile()
image = tempfile.NamedTemporaryFile(suffix="." + infile.split(".")[-1].split("/")[-1]) image = tempfile.NamedTemporaryFile(suffix=extension)
with open(infile, "rb") as inimage: image.write(infile.read())
image.write(inimage.read())
erect = ["erect2cubic", f"--erect={image.name}", f"--ptofile={pto.name}", "--filespec=PNG_m"] erect = ["erect2cubic", f"--erect={image.name}", f"--ptofile={pto.name}", "--filespec=PNG_m"]
subprocess.run(erect) subprocess.run(erect)
tiles = tempfile.TemporaryDirectory() tiles = tempfile.TemporaryDirectory()
nona = ["nona", pto.name, "-o", tiles.name + "/out"] nona = ["nona", pto.name, "-o", tiles.name + "/out"]
subprocess.run(nona) subprocess.run(nona)
return PIL.Image.open(tiles.name + "/out0005.png") image = PythonMagick.Image(tiles.name + "/out0005.png")
geo = PythonMagick.Geometry(int(image.baseColumns() / 3), int(image.baseColumns() / 3), int(image.baseColumns() / 3), int(image.baseColumns() / 3))
image.crop(geo)
return image

View file

@ -78,7 +78,7 @@ class Content(Model):
class Media(Model): class Media(Model):
uuid = UUIDField(primary_key=True) uuid = UUIDField(primary_key=True)
code = ForeignKey(Content, CASCADE) content = ForeignKey(Content, CASCADE)
@classmethod @classmethod
def generate_uuid(cls): def generate_uuid(cls):

View file

@ -15,7 +15,7 @@ Including another URLconf
""" """
from django.urls import path from django.urls import path
from core.views import APICreateSeries, APISeriesByIDDispatcher, APICodesBySeriesIDDispatcher, APICreateCodes, APICodeByID from core.views import APICreateSeries, APISeriesByIDDispatcher, APICodesBySeriesIDDispatcher, APICreateCodes, APICodeByID, APIAnalyzeContent
urlpatterns = [ urlpatterns = [
path('series/', APICreateSeries.as_view()), path('series/', APICreateSeries.as_view()),
@ -24,4 +24,5 @@ urlpatterns = [
path('codes/', APICreateCodes.as_view()), path('codes/', APICreateCodes.as_view()),
path('codes/<uuid>/', APICodeByID.as_view()), path('codes/<uuid>/', APICodeByID.as_view()),
path('codes/<seriesid>/<codeid>/', APICodeByID.as_view()), path('codes/<seriesid>/<codeid>/', APICodeByID.as_view()),
path('content/', APIAnalyzeContent.as_view()),
] ]

View file

@ -14,7 +14,12 @@ from io import BytesIO
import urllib.request import urllib.request
from core.models import Series, APIKey, Code import boto3
from core.models import Series, APIKey, Code, Media, Content
from customsettings import AWS_ACCESS_KEY_ID, AWS_BUCKET, AWS_SECRET_ACCESS_KEY
from converter import convert
from reader import read_code
class APIView(View): class APIView(View):
@method_decorator(csrf_exempt) @method_decorator(csrf_exempt)
@ -224,13 +229,62 @@ class APICodeByID(CodeAPIView):
class APIAnalyzeContent(APIView): class APIAnalyzeContent(APIView):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
url = request.body.decode("utf-8") data = json.loads(request.body.decode("utf-8"))
if data.get("url"):
try:
URLValidator()(data["url"])
content = BytesIO(urllib.request.urlopen(data["url"]).read())
extension = "." + data["url"].split(".")[-1]
except:
return JsonResponse({"error": "Failed to retrieve file %s" % data["url"]})
try: else:
val = URLValidator().val(url) try:
except ValidationError: session = boto3.Session(aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
return JsonResponse({"error": "Failed to validate URL"}) s3 = session.resource("s3")
bucket = s3.Bucket(AWS_BUCKET)
content = BytesIO()
bucket.download_fileobj(data["path"], content)
extension = "." + data["path"].split(".")[-1]
except:
return JsonResponse({"error": "Failed to retrieve file %s" % data["path"]})
content = BytesIO(urllib.request.urlopen('url').read()) content.seek(0)
down = convert(content, extension)
literal = read_code(down)
if literal:
code = None
if len(literal.split(":")) == 3:
seriesid = literal.split(":")[1]
codeid = literal.split(":")[2]
try:
code = Code.objects.get(id=codeid, series=Series.objects.get(id=seriesid))
parsed = code.title
except (Code.DoesNotExist, Series.DoesNotExist):
return JsonResponse({"error": "No code found for Series %s Code %s" % (seriesid, codeid)})
else:
parsed = ":".join(literal.split(":")[1:])
content = Content.objects.create(literal=literal)
media = Media.objects.create(content=content)
output = {
"uuid": media.uuid,
"literal": media.content.literal
}
if code:
output["parsed"] = parsed
output["code"] = model_to_dict(code)
output["code"]["series"] = model_to_dict(code.series)
else:
output = {"error": "No code found in provided image"}
return JsonResponse(output)

View file

@ -2,10 +2,13 @@
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'me98p&0-ijj-*vov@vm_&z&x#gr9uvvc9*y$n!!%=+javz^-#7' SECRET_KEY = 'somesecretstring'
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = True
ALLOWED_HOSTS = [] ALLOWED_HOSTS = []
AWS_BUCKET = "bucket"
AWS_ACCESS_KEY_ID = "accesskey"
AWS_SECRET_ACCESS_KEY = "secretkey"

View file

@ -322,6 +322,8 @@ paths:
schema: schema:
url: url:
type: string type: string
path:
type: string
uuid: uuid:
type: string type: string
format: uuid format: uuid

View file

@ -11,14 +11,13 @@ class QRCode:
self.content = content self.content = content
self.rect = rect self.rect = rect
def read_code(imagepath): def read_code(image):
image = PIL.Image.open(imagepath)
reader = zxing.BarCodeReader() reader = zxing.BarCodeReader()
codes = [] codes = []
for _ in range(10): for _ in range(10):
tempimage = tempfile.NamedTemporaryFile() tempimage = tempfile.NamedTemporaryFile(suffix=".png")
image.save(tempimage, format="png") image.write(tempimage.name)
zxcontent = reader.decode(tempimage.name) zxcontent = reader.decode(tempimage.name)
zbcontent = pyzbar.pyzbar.decode(PIL.Image.open(tempimage.name)) zbcontent = pyzbar.pyzbar.decode(PIL.Image.open(tempimage.name))
content = [] content = []
@ -30,13 +29,11 @@ def read_code(imagepath):
content.append(single.data.decode()) content.append(single.data.decode())
for code in content: for code in content:
if not code in codes: if code.startswith("EXP360:"):
codes.append(code) return code
if codes: image.modulate(150, 100, 100)
return codes image.contrast(150)
image = PIL.ImageEnhance.Contrast(image).enhance(2.5)
if __name__ == "__main__": if __name__ == "__main__":
content = read_code(sys.argv[1]) content = read_code(sys.argv[1])

View file

@ -1,4 +1,8 @@
django django
pyqrcode pyqrcode
PIL pillow
numpy numpy
boto3
pyzbar
numpy
zxing