refactor: project structure, makefile

This commit is contained in:
2025-11-25 18:25:06 +03:00
parent d367dd0909
commit e5fe816325
13 changed files with 996 additions and 5 deletions

89
internal/vision/vision.go Normal file
View File

@@ -0,0 +1,89 @@
// Copyright (c) 2025 Nikolai Papin
//
// This file is part of the Auto Attendance app that looks for
// self-attend QR-codes during lectures and opens their URLs in your
// browser.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
// the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package vision
import (
"errors"
"git.weirdcat.su/weirdcat/auto-attendance/internal/logger"
"github.com/makiuchi-d/gozxing"
"github.com/makiuchi-d/gozxing/qrcode"
"gocv.io/x/gocv"
)
type Vision interface {
AnalyzeImage(filePath string) (data VisionData, err error)
}
type visionImpl struct {
log *logger.Logger
}
var (
ErrImageEmpty = errors.New("Image from file was empty")
)
// AnalyzeImage implements Vision.
func (v *visionImpl) AnalyzeImage(filePath string) (data VisionData, err error) {
// TODO: scanning for multiple QR-codes at once
v.log.Debug("analyzing image for qr codes", "filePath", filePath)
img := gocv.IMRead(filePath, gocv.IMReadColor)
if img.Empty() {
v.log.Error("could not read image file", "filePath", filePath)
return VisionData{}, ErrImageEmpty
}
defer img.Close()
// Convert to grayscale for QR code detection
gray := gocv.NewMat()
defer gray.Close()
gocv.CvtColor(img, &gray, gocv.ColorBGRToGray)
// Convert gocv.Mat to image.Image for gozxing
imgGray, err := gray.ToImage()
if err != nil {
v.log.Error("failed to convert image", "error", err)
return VisionData{}, err
}
// Create a binary bitmap from the image
bmp, err := gozxing.NewBinaryBitmapFromImage(imgGray)
if err != nil {
v.log.Error("failed to create binary bitmap", "error", err)
return VisionData{}, err
}
reader := qrcode.NewQRCodeReader()
result, err := reader.Decode(bmp, nil)
if err != nil {
v.log.Debug("no qr code found in image", "filePath", filePath, "error", err)
return VisionData{}, nil
}
v.log.Info("QR code decoded successfully", "content", result.GetText())
data = VisionData{result.GetText()}
return data, nil
}
func NewVision(log *logger.Logger) Vision {
return &visionImpl{log: log}
}