That ought to do.
This commit is contained in:
parent
ff97a4845b
commit
b2e760053f
9 changed files with 95 additions and 30 deletions
|
@ -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:
|
||||
|
||||
* Perl and the erect2cubic package
|
||||
* Hugin (incl. Nona)
|
||||
* Hugin (incl. Nona)
|
||||
* Java and zxing
|
||||
* PythonMagick
|
|
@ -1,15 +1,17 @@
|
|||
import tempfile
|
||||
import subprocess
|
||||
import PIL.Image
|
||||
import PythonMagick
|
||||
|
||||
def convert(infile):
|
||||
def convert(infile, extension):
|
||||
pto = tempfile.NamedTemporaryFile()
|
||||
image = tempfile.NamedTemporaryFile(suffix="." + infile.split(".")[-1].split("/")[-1])
|
||||
with open(infile, "rb") as inimage:
|
||||
image.write(inimage.read())
|
||||
image = tempfile.NamedTemporaryFile(suffix=extension)
|
||||
image.write(infile.read())
|
||||
erect = ["erect2cubic", f"--erect={image.name}", f"--ptofile={pto.name}", "--filespec=PNG_m"]
|
||||
subprocess.run(erect)
|
||||
tiles = tempfile.TemporaryDirectory()
|
||||
nona = ["nona", pto.name, "-o", tiles.name + "/out"]
|
||||
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
|
|
@ -78,7 +78,7 @@ class Content(Model):
|
|||
|
||||
class Media(Model):
|
||||
uuid = UUIDField(primary_key=True)
|
||||
code = ForeignKey(Content, CASCADE)
|
||||
content = ForeignKey(Content, CASCADE)
|
||||
|
||||
@classmethod
|
||||
def generate_uuid(cls):
|
||||
|
|
|
@ -15,7 +15,7 @@ Including another URLconf
|
|||
"""
|
||||
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 = [
|
||||
path('series/', APICreateSeries.as_view()),
|
||||
|
@ -24,4 +24,5 @@ urlpatterns = [
|
|||
path('codes/', APICreateCodes.as_view()),
|
||||
path('codes/<uuid>/', APICodeByID.as_view()),
|
||||
path('codes/<seriesid>/<codeid>/', APICodeByID.as_view()),
|
||||
path('content/', APIAnalyzeContent.as_view()),
|
||||
]
|
||||
|
|
|
@ -14,7 +14,12 @@ from io import BytesIO
|
|||
|
||||
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):
|
||||
@method_decorator(csrf_exempt)
|
||||
|
@ -224,13 +229,62 @@ class APICodeByID(CodeAPIView):
|
|||
|
||||
class APIAnalyzeContent(APIView):
|
||||
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:
|
||||
val = URLValidator().val(url)
|
||||
except ValidationError:
|
||||
return JsonResponse({"error": "Failed to validate URL"})
|
||||
else:
|
||||
try:
|
||||
session = boto3.Session(aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
|
||||
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)
|
|
@ -2,10 +2,13 @@
|
|||
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
|
||||
|
||||
# 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!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
AWS_BUCKET = "bucket"
|
||||
AWS_ACCESS_KEY_ID = "accesskey"
|
||||
AWS_SECRET_ACCESS_KEY = "secretkey"
|
||||
|
|
|
@ -322,6 +322,8 @@ paths:
|
|||
schema:
|
||||
url:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
uuid:
|
||||
type: string
|
||||
format: uuid
|
||||
|
|
|
@ -11,14 +11,13 @@ class QRCode:
|
|||
self.content = content
|
||||
self.rect = rect
|
||||
|
||||
def read_code(imagepath):
|
||||
image = PIL.Image.open(imagepath)
|
||||
def read_code(image):
|
||||
reader = zxing.BarCodeReader()
|
||||
codes = []
|
||||
|
||||
for _ in range(10):
|
||||
tempimage = tempfile.NamedTemporaryFile()
|
||||
image.save(tempimage, format="png")
|
||||
tempimage = tempfile.NamedTemporaryFile(suffix=".png")
|
||||
image.write(tempimage.name)
|
||||
zxcontent = reader.decode(tempimage.name)
|
||||
zbcontent = pyzbar.pyzbar.decode(PIL.Image.open(tempimage.name))
|
||||
content = []
|
||||
|
@ -30,13 +29,11 @@ def read_code(imagepath):
|
|||
content.append(single.data.decode())
|
||||
|
||||
for code in content:
|
||||
if not code in codes:
|
||||
codes.append(code)
|
||||
if code.startswith("EXP360:"):
|
||||
return code
|
||||
|
||||
if codes:
|
||||
return codes
|
||||
|
||||
image = PIL.ImageEnhance.Contrast(image).enhance(2.5)
|
||||
image.modulate(150, 100, 100)
|
||||
image.contrast(150)
|
||||
|
||||
if __name__ == "__main__":
|
||||
content = read_code(sys.argv[1])
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
django
|
||||
pyqrcode
|
||||
PIL
|
||||
numpy
|
||||
pillow
|
||||
numpy
|
||||
boto3
|
||||
pyzbar
|
||||
numpy
|
||||
zxing
|
Loading…
Reference in a new issue