Initial commit
This commit is contained in:
		
						commit
						1544855377
					
				
					 20 changed files with 743 additions and 0 deletions
				
			
		
							
								
								
									
										0
									
								
								photos/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								photos/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										10
									
								
								photos/admin.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								photos/admin.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
from django.contrib import admin
 | 
			
		||||
from django.contrib.admin import ModelAdmin
 | 
			
		||||
 | 
			
		||||
from photos.models import Photo
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@admin.register(Photo)
 | 
			
		||||
class PhotoAdmin(ModelAdmin):
 | 
			
		||||
    fields = ('image_tag', 'added_on')
 | 
			
		||||
    readonly_fields = ('image_tag', 'added_on')
 | 
			
		||||
							
								
								
									
										5
									
								
								photos/apps.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								photos/apps.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
from django.apps import AppConfig
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PhotosConfig(AppConfig):
 | 
			
		||||
    name = 'photos'
 | 
			
		||||
							
								
								
									
										22
									
								
								photos/migrations/0001_initial.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								photos/migrations/0001_initial.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
# Generated by Django 2.0.5 on 2018-05-21 18:53
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    initial = True
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.CreateModel(
 | 
			
		||||
            name='Photo',
 | 
			
		||||
            fields=[
 | 
			
		||||
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
			
		||||
                ('photo', models.ImageField(upload_to='photos')),
 | 
			
		||||
                ('added_on', models.DateTimeField(auto_now_add=True)),
 | 
			
		||||
            ],
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										0
									
								
								photos/migrations/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								photos/migrations/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										17
									
								
								photos/models.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								photos/models.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
from django.conf import settings
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.utils.safestring import mark_safe
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Photo(models.Model):
 | 
			
		||||
    photo = models.ImageField(upload_to="photos")
 | 
			
		||||
    added_on = models.DateTimeField(auto_now_add=True)
 | 
			
		||||
 | 
			
		||||
    def get_absolute_url(self):
 | 
			
		||||
        from django.urls import reverse
 | 
			
		||||
        return "{}{}".format(settings.BASE_URL, reverse("show", kwargs={'pk': self.id}))
 | 
			
		||||
 | 
			
		||||
    def image_tag(self):
 | 
			
		||||
        return mark_safe('<img src="{}" />'.format(self.get_absolute_url()))
 | 
			
		||||
 | 
			
		||||
    image_tag.short_description = 'Image'
 | 
			
		||||
							
								
								
									
										12
									
								
								photos/static/jpeg_camera_with_dependencies.min.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								photos/static/jpeg_camera_with_dependencies.min.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								photos/static/loader.gif
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								photos/static/loader.gif
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 1.7 KiB  | 
							
								
								
									
										58
									
								
								photos/static/photo.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								photos/static/photo.css
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,58 @@
 | 
			
		|||
body {
 | 
			
		||||
  background-color: #ddd;
 | 
			
		||||
  padding: 0.5em;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  font-family: "Helvetica Neueu", "Helvetica", "Arial", sans;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button, input, #loader {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input {
 | 
			
		||||
  width: 300px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#camera {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  background-color: #eee;
 | 
			
		||||
  width: 1280px;
 | 
			
		||||
  height: 650px;
 | 
			
		||||
  margin: 0.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#camera .placeholder {
 | 
			
		||||
  padding: 0.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#snapshots {
 | 
			
		||||
  height: 150px;
 | 
			
		||||
  margin: 0.5em 0;
 | 
			
		||||
  padding: 3px;
 | 
			
		||||
 | 
			
		||||
  border: 1px solid #aaa;
 | 
			
		||||
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
  overflow-x: auto;
 | 
			
		||||
  overflow-y: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#snapshots canvas, #snapshots img {
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  -webkit-box-sizing: border-box;
 | 
			
		||||
  -moz-box-sizing: border-box;
 | 
			
		||||
  -ms-box-sizing: border-box;
 | 
			
		||||
  -o-box-sizing: border-box;
 | 
			
		||||
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  margin-left: 3px;
 | 
			
		||||
  border: 3px solid transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#snapshots .selected {
 | 
			
		||||
  border: 3px solid #000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button, #upload_status, #upload_result, #loader {
 | 
			
		||||
  margin: 0.5em;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										153
									
								
								photos/static/photo.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								photos/static/photo.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,153 @@
 | 
			
		|||
$(function() {
 | 
			
		||||
  if (window.JpegCamera) {
 | 
			
		||||
    var camera; // Initialized at the end
 | 
			
		||||
    //var url = "https://isonzeinterndronken.nl/11bt/photos.json/";
 | 
			
		||||
    var url = "http://localhost:8000/new/";
 | 
			
		||||
 | 
			
		||||
    var update_stream_stats = function(stats) {
 | 
			
		||||
      $("#stream_stats").html(
 | 
			
		||||
	"Mean luminance = " + stats.mean +
 | 
			
		||||
	"; Standard Deviation = " + stats.std);
 | 
			
		||||
 | 
			
		||||
      setTimeout(function() {camera.get_stats(update_stream_stats);}, 1000);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var take_snapshots = function(count) {
 | 
			
		||||
      var snapshot = camera.capture();
 | 
			
		||||
 | 
			
		||||
      if (JpegCamera.canvas_supported()) {
 | 
			
		||||
	snapshot.get_canvas(add_snapshot);
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
	// <canvas> is not supported in this browser. We'll use anonymous
 | 
			
		||||
	// graphic instead.
 | 
			
		||||
	var image = document.createElement("img");
 | 
			
		||||
	image.src = "no_canvas_photo.jpg";
 | 
			
		||||
	setTimeout(function() {add_snapshot.call(snapshot, image)}, 1);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (count > 1) {
 | 
			
		||||
	setTimeout(function() {take_snapshots(count - 1);}, 500);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var add_snapshot = function(element) {
 | 
			
		||||
      $(element).data("snapshot", this).addClass("item");
 | 
			
		||||
 | 
			
		||||
      var $container = $("#snapshots").append(element);
 | 
			
		||||
      var $camera = $("#camera");
 | 
			
		||||
      var camera_ratio = $camera.innerWidth() / $camera.innerHeight();
 | 
			
		||||
 | 
			
		||||
      var height = $container.height()
 | 
			
		||||
      element.style.height = "" + height + "px";
 | 
			
		||||
      element.style.width = "" + Math.round(camera_ratio * height) + "px";
 | 
			
		||||
 | 
			
		||||
      var scroll = $container[0].scrollWidth - $container.innerWidth();
 | 
			
		||||
 | 
			
		||||
      $container.animate({
 | 
			
		||||
	scrollLeft: scroll
 | 
			
		||||
      }, 200);
 | 
			
		||||
      clear_upload_data();
 | 
			
		||||
      $("#loader").show();
 | 
			
		||||
      snapshot = $(element).data("snapshot");
 | 
			
		||||
      snapshot.upload({api_url: url}).done(upload_done).fail(upload_fail);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var select_snapshot = function () {
 | 
			
		||||
      $(".item").removeClass("selected");
 | 
			
		||||
      var snapshot = $(this).addClass("selected").data("snapshot");
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var clear_upload_data = function() {
 | 
			
		||||
      $("#upload_status, #upload_result").html("");
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var upload_snapshot = function() {
 | 
			
		||||
      var api_url = $("#api_url").val();
 | 
			
		||||
 | 
			
		||||
      if (!api_url.length) {
 | 
			
		||||
	$("#upload_status").html("Please provide URL for the upload");
 | 
			
		||||
	return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      clear_upload_data();
 | 
			
		||||
      $("#loader").show();
 | 
			
		||||
      $("#upload_snapshot").prop("disabled", true);
 | 
			
		||||
 | 
			
		||||
      var snapshot = $(".item.selected").data("snapshot");
 | 
			
		||||
      snapshot.upload({api_url: url}).done(upload_done).fail(upload_fail);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var upload_done = function(response) {
 | 
			
		||||
      $("#upload_snapshot").prop("disabled", false);
 | 
			
		||||
      $("#loader").hide();
 | 
			
		||||
      $("#upload_status").html("Upload successful");
 | 
			
		||||
      $("#upload_result").html(response);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var upload_fail = function(code, error, response) {
 | 
			
		||||
      $("#upload_snapshot").prop("disabled", false);
 | 
			
		||||
      $("#loader").hide();
 | 
			
		||||
      $("#upload_status").html(
 | 
			
		||||
	"Upload failed with status " + code + " (" + error + ")");
 | 
			
		||||
      $("#upload_result").html(response);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var discard_snapshot = function() {
 | 
			
		||||
      var element = $(".item.selected").removeClass("item selected");
 | 
			
		||||
 | 
			
		||||
      var next = element.nextAll(".item").first();
 | 
			
		||||
 | 
			
		||||
      if (!next.size()) {
 | 
			
		||||
	next = element.prevAll(".item").first();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (next.size()) {
 | 
			
		||||
	next.addClass("selected");
 | 
			
		||||
	next.data("snapshot").show();
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
	hide_snapshot_controls();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      element.data("snapshot").discard();
 | 
			
		||||
 | 
			
		||||
      element.hide("slow", function() {$(this).remove()});
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var show_stream = function() {
 | 
			
		||||
      $(this).hide();
 | 
			
		||||
      $(".item").removeClass("selected");
 | 
			
		||||
      hide_snapshot_controls();
 | 
			
		||||
      clear_upload_data();
 | 
			
		||||
      camera.show_stream();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var hide_snapshot_controls = function() {
 | 
			
		||||
      $("#discard_snapshot, #upload_snapshot, #api_url").hide();
 | 
			
		||||
      $("#upload_result, #upload_status").html("");
 | 
			
		||||
      $("#show_stream").hide();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    $("#take_snapshots").click(function() {take_snapshots(1);});
 | 
			
		||||
    $("#snapshots").on("click", ".item", select_snapshot);
 | 
			
		||||
    $("#upload_snapshot").click(upload_snapshot);
 | 
			
		||||
    $("#discard_snapshot").click(discard_snapshot);
 | 
			
		||||
    $("#show_stream").click(show_stream);
 | 
			
		||||
    $(document).on("keypress", function (e) {
 | 
			
		||||
      take_snapshots(1);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    var options = {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    camera = new JpegCamera("#camera", options).ready(function(info) {
 | 
			
		||||
      //$("#take_snapshots").show();
 | 
			
		||||
 | 
			
		||||
      $("#camera_info").html(
 | 
			
		||||
	"Camera resolution: " + info.video_width + "x" + info.video_height);
 | 
			
		||||
 | 
			
		||||
      this.get_stats(update_stream_stats);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										43
									
								
								photos/static/tags
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								photos/static/tags
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										3
									
								
								photos/tests.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								photos/tests.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
from django.test import TestCase
 | 
			
		||||
 | 
			
		||||
# Create your tests here.
 | 
			
		||||
							
								
								
									
										43
									
								
								photos/views.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								photos/views.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,43 @@
 | 
			
		|||
import io
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
from PIL import Image
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.core.files.storage import default_storage
 | 
			
		||||
from django.http import JsonResponse, Http404, HttpResponse
 | 
			
		||||
from django.shortcuts import render
 | 
			
		||||
from django.utils.datetime_safe import datetime
 | 
			
		||||
 | 
			
		||||
from django.views.decorators.http import require_POST
 | 
			
		||||
 | 
			
		||||
from photos.models import Photo
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def index(request):
 | 
			
		||||
    return render(request, 'index.html')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def show(request, pk):
 | 
			
		||||
    try:
 | 
			
		||||
        photo = Photo.objects.get(pk=pk)
 | 
			
		||||
        with open(photo.photo.path, "rb") as f:
 | 
			
		||||
            return HttpResponse(f.read(), content_type="image/jpeg")
 | 
			
		||||
    except Photo.DoesNotExist:
 | 
			
		||||
        raise Http404()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def photo_list(request):
 | 
			
		||||
    return JsonResponse([{
 | 
			
		||||
        'id': p.id,
 | 
			
		||||
        'created_at': str(p.added_on),
 | 
			
		||||
        'updated_at': str(p.added_on),
 | 
			
		||||
        'url': p.get_absolute_url(),
 | 
			
		||||
    } for p in Photo.objects.all().order_by('-id')], safe=False)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@require_POST
 | 
			
		||||
def file_upload(request):
 | 
			
		||||
    save_path = os.path.join(settings.MEDIA_ROOT, 'photos', "{}.jpg".format(datetime.now()))
 | 
			
		||||
    path = default_storage.save(save_path, request)
 | 
			
		||||
    photo = Photo.objects.create(photo=path)
 | 
			
		||||
    return JsonResponse({'picture': photo.id})
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue