diff --git a/handler-index.go b/handler-index.go
index aec3cd562bbb9b1305245f512f7f97b530c79416..e7405e58ee1a877c5801d9e3d31bac057c3907cf 100644
--- a/handler-index.go
+++ b/handler-index.go
@@ -4,14 +4,9 @@ import (
 	"errors"
 	"fmt"
 	"html/template"
-	"image"
 	"log"
 	"net/http"
 	"strconv"
-
-	// Imported for side effects to register format handlers
-	_ "image/jpeg"
-	_ "image/png"
 )
 
 var indexTemplate = template.Must(template.ParseFS(templateFS, "templates/base.tpl", "templates/index.tpl"))
@@ -86,25 +81,11 @@ func (h Handler) index(w http.ResponseWriter, r *http.Request) {
 		}
 		defer picFile.Close()
 
-		mime := picHdr.Header.Get("Content-Type")
-		switch mime {
-		case "image/jpeg", "image/png":
-		default:
-			httpError(w, "can't load picture", errors.New("invalid mime type: "+mime), http.StatusBadRequest)
-			return
-		}
-
-		log.Println("picture", picHdr.Size, picHdr.Header.Get("Content-Type"))
-
-		img, imgFmt, err := image.Decode(picFile)
+		err = vino.AddPicture(picFile, picHdr.Header.Get("Content-Type"))
 		if err != nil {
-			httpError(w, "can't read picture file", err, http.StatusInternalServerError)
+			httpError(w, "can't load picture", err, http.StatusBadRequest)
 			return
 		}
-
-		log.Println("got a", imgFmt, "for the picture")
-
-		vino.Picture = img
 	}
 
 	err = vino.Store(r.Context(), h.db, Add)
diff --git a/vino.go b/vino.go
index 1f30ca82f2b8d4a2b355397accdca05b19a8a351..f3242e7e6ddba5e195caa2ef6346df1b9f020529 100644
--- a/vino.go
+++ b/vino.go
@@ -3,11 +3,17 @@ package main
 import (
 	"bytes"
 	"context"
+	"errors"
 	"fmt"
 	"image"
 	"image/png"
+	"io"
 	"log"
 
+	// Imported for side effects to register format handlers
+	_ "image/jpeg"
+	_ "image/png"
+
 	"github.com/Masterminds/squirrel"
 	"github.com/jmoiron/sqlx"
 	"golang.org/x/image/draw"
@@ -76,6 +82,27 @@ func LoadPictureData(ctx context.Context, db *sqlx.DB, id int) ([]byte, error) {
 	return img, nil
 }
 
+// AddPicture loads picture data (PNG or JPEG) from fh and sets v's picture to it.
+// If something goes wrong during loading, or the image is neither PNG nor JPEG, an error
+// is returned. If contentType is not the empty string, it is validated to be either
+// image/png or image/jpeg
+func (v *Vino) AddPicture(fh io.Reader, contentType string) error {
+	switch contentType {
+	case "", "image/jpeg", "image/png":
+	default:
+		return fmt.Errorf("unexpected content type for image: %q", contentType)
+	}
+
+	img, _, err := image.Decode(fh)
+	if err != nil {
+		return err
+	}
+
+	v.Picture = img
+
+	return nil
+}
+
 func (v Vino) String() string {
 	return fmt.Sprintf("{Name: %q, Rating: %d}", v.Name, v.Rating)
 }