mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-10-28 04:05:21 +08:00
feature (plg_image_*): support for new images and cleanup
This commit is contained in:
6
go.mod
6
go.mod
@ -25,6 +25,8 @@ require (
|
||||
github.com/rasky/go-xdr v0.0.0-20170124162913-1a41d1a06c93 // indirect
|
||||
github.com/rogpeppe/go-internal v1.8.0 // indirect
|
||||
github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4 // indirect
|
||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef
|
||||
github.com/suyashkumar/dicom v1.0.5
|
||||
github.com/tidwall/gjson v1.13.0
|
||||
github.com/tidwall/sjson v1.0.4
|
||||
@ -32,8 +34,8 @@ require (
|
||||
github.com/vmware/go-nfs-client v0.0.0-20190605212624-d43b92724c1b
|
||||
github.com/wayneashleyberry/terminal-dimensions v1.1.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838
|
||||
golang.org/x/image v0.0.0-20210622092929-e6eecd499c2c
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410
|
||||
golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9
|
||||
|
||||
9
go.sum
9
go.sum
@ -245,6 +245,11 @@ github.com/spacemonkeygo/monkit/v3 v3.0.17/go.mod h1:kj1ViJhlyADa7DiA4xVnTuPA46l
|
||||
github.com/spacemonkeygo/monotime v0.0.0-20180824235756-e3f48a95f98a/go.mod h1:ul4bvvnCOPZgq8w0nTkSmWVg/hauVpFS97Am1YM1XXo=
|
||||
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
|
||||
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
|
||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
|
||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q=
|
||||
github.com/srwiley/rasterx v0.0.0-20210519020934-456a8d69b780/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU=
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
|
||||
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
@ -310,6 +315,8 @@ golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/image v0.0.0-20210622092929-e6eecd499c2c h1:FRR4fGZm/CMwZka5baQ4z8c8StbxJOMjS/45e0BAxK0=
|
||||
golang.org/x/image v0.0.0-20210622092929-e6eecd499c2c/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
@ -343,6 +350,8 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4 h1:DZshvxDdVoeKIbudAdFEKi+f70l51luSy/7b76ibTY0=
|
||||
golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
||||
@ -28,8 +28,8 @@ import (
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_editor_onlyoffice"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_handler_console"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_image_ascii"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_image_dicom"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_image_thumbnail"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_image_transcode"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_search_stateless"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_security_scanner"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_security_svg"
|
||||
|
||||
@ -1,64 +0,0 @@
|
||||
package plg_image_dicom
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"github.com/suyashkumar/dicom"
|
||||
"github.com/suyashkumar/dicom/pkg/tag"
|
||||
"image/jpeg"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Hooks.Register.ProcessFileContentBeforeSend(renderDicom)
|
||||
}
|
||||
|
||||
func renderDicom(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
|
||||
query := req.URL.Query()
|
||||
if query.Get("size") == "" {
|
||||
return reader, nil
|
||||
} else if GetMimeType(query.Get("path")) != "image/dicom" {
|
||||
return reader, nil
|
||||
}
|
||||
var b bytes.Buffer
|
||||
w := bufio.NewWriter(&b)
|
||||
io.Copy(w, reader)
|
||||
reader.Close()
|
||||
dataset, err := dicom.Parse(&b, int64(len(b.Bytes())), nil)
|
||||
if err != nil {
|
||||
Log.Debug("plg_image_dicom::parse '%s'", err.Error())
|
||||
return nil, ErrNotValid
|
||||
}
|
||||
pixelDataElement, err := dataset.FindElementByTag(tag.PixelData)
|
||||
if err != nil {
|
||||
Log.Debug("plg_image_dicom::findElementByTag '%s'", err.Error())
|
||||
return nil, ErrNotValid
|
||||
}
|
||||
pixelDataInfo := dicom.MustGetPixelDataInfo(pixelDataElement.Value)
|
||||
|
||||
for _, fr := range pixelDataInfo.Frames {
|
||||
img, err := fr.GetImage()
|
||||
if err != nil {
|
||||
if err.Error() == "unsupported JPEG feature: unknown marker" {
|
||||
// known issue with lossless jpeg codec which isn't supported in golang
|
||||
// and is not trivial to support in Filestash
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
Log.Stdout("plg_image_dicom::getImage '%s'", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
var b bytes.Buffer
|
||||
w := bufio.NewWriter(&b)
|
||||
err = jpeg.Encode(w, img, &jpeg.Options{Quality: 100})
|
||||
if err != nil {
|
||||
Log.Debug("plg_image_dicom::encode '%s'", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
h := (*res).Header()
|
||||
h.Set("Content-Type", "image/jpeg")
|
||||
return NewReadCloserFromReader(&b), nil
|
||||
}
|
||||
return nil, ErrNotValid
|
||||
}
|
||||
@ -23,9 +23,6 @@ func init() {
|
||||
for _, mType := range []string{
|
||||
"image/x-canon-cr2", "image/x-fuji-raf", "image/x-nikon-nef",
|
||||
"image/x-nikon-nrw", "image/x-epson-erf",
|
||||
// "image/tiff",
|
||||
// "image/x-kodak-dcr", "image/x-hasselblad-3fr",
|
||||
// "image/x-raw",
|
||||
} {
|
||||
Hooks.Register.Thumbnailer(mType, thumbnailBuilder{thumbnailRaw})
|
||||
}
|
||||
|
||||
45
server/plugin/plg_image_transcode/index.go
Normal file
45
server/plugin/plg_image_transcode/index.go
Normal file
@ -0,0 +1,45 @@
|
||||
package plg_image_transcode
|
||||
|
||||
import (
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Hooks.Register.ProcessFileContentBeforeSend(renderImages)
|
||||
}
|
||||
|
||||
func renderImages(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
|
||||
query := req.URL.Query()
|
||||
if query.Get("thumbnail") == "true" {
|
||||
return reader, nil
|
||||
} else if query.Get("size") == "" {
|
||||
return reader, nil
|
||||
}
|
||||
|
||||
var (
|
||||
out io.ReadCloser = nil
|
||||
err error = nil
|
||||
)
|
||||
mType := GetMimeType(query.Get("path"))
|
||||
switch mType {
|
||||
case "image/x-ms-bmp":
|
||||
out, mType, err = transcodeBmp(reader)
|
||||
case "image/tiff":
|
||||
out, mType, err = transcodeTiff(reader)
|
||||
case "image/dicom":
|
||||
out, mType, err = transcodeDicom(reader)
|
||||
default:
|
||||
err = ErrNotImplemented
|
||||
}
|
||||
reader.Close()
|
||||
if err == nil {
|
||||
(*res).Header().Set("Content-Type", mType)
|
||||
}
|
||||
if err != nil && err != ErrNotImplemented && err != ErrNotValid {
|
||||
Log.Debug("plg_image_transcode::err %s", err.Error())
|
||||
return nil, ErrNotValid
|
||||
}
|
||||
return out, err
|
||||
}
|
||||
26
server/plugin/plg_image_transcode/transcode_bmp.go
Normal file
26
server/plugin/plg_image_transcode/transcode_bmp.go
Normal file
@ -0,0 +1,26 @@
|
||||
package plg_image_transcode
|
||||
|
||||
import (
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
_ "golang.org/x/image/bmp"
|
||||
"image"
|
||||
"image/jpeg"
|
||||
"io"
|
||||
)
|
||||
|
||||
func transcodeBmp(reader io.Reader) (io.ReadCloser, string, error) {
|
||||
img, _, err := image.Decode(reader)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
r, w := io.Pipe()
|
||||
go func() {
|
||||
err := jpeg.Encode(w, img, &jpeg.Options{Quality: 80})
|
||||
w.Close()
|
||||
if err != nil {
|
||||
Log.Debug("plg_image_transcode::bmp jpeg encoding error '%s'", err.Error())
|
||||
}
|
||||
}()
|
||||
return NewReadCloserFromReader(r), "image/jpeg", nil
|
||||
}
|
||||
53
server/plugin/plg_image_transcode/transcode_dicom.go
Normal file
53
server/plugin/plg_image_transcode/transcode_dicom.go
Normal file
@ -0,0 +1,53 @@
|
||||
package plg_image_transcode
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"github.com/suyashkumar/dicom"
|
||||
"github.com/suyashkumar/dicom/pkg/tag"
|
||||
"image/jpeg"
|
||||
"io"
|
||||
)
|
||||
|
||||
func transcodeDicom(reader io.Reader) (io.ReadCloser, string, error) {
|
||||
var b bytes.Buffer
|
||||
w := bufio.NewWriter(&b)
|
||||
io.Copy(w, reader)
|
||||
|
||||
dataset, err := dicom.Parse(&b, int64(len(b.Bytes())), nil)
|
||||
if err != nil {
|
||||
Log.Debug("plg_image_transcode::dicom::parse '%s'", err.Error())
|
||||
return nil, "", ErrNotValid
|
||||
}
|
||||
pixelDataElement, err := dataset.FindElementByTag(tag.PixelData)
|
||||
if err != nil {
|
||||
Log.Debug("plg_image_transcode::dicom::findElementByTag '%s'", err.Error())
|
||||
return nil, "", ErrNotValid
|
||||
}
|
||||
pixelDataInfo := dicom.MustGetPixelDataInfo(pixelDataElement.Value)
|
||||
|
||||
for _, fr := range pixelDataInfo.Frames {
|
||||
img, err := fr.GetImage()
|
||||
if err != nil {
|
||||
if err.Error() == "unsupported JPEG feature: unknown marker" {
|
||||
// known issue with lossless jpeg codec which isn't supported in golang
|
||||
// and is not trivial to support in Filestash
|
||||
return nil, "", ErrNotImplemented
|
||||
}
|
||||
Log.Stdout("plg_image_transcode_dicom::getImage '%s'", err.Error())
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
r, w := io.Pipe()
|
||||
go func() {
|
||||
err := jpeg.Encode(w, img, &jpeg.Options{Quality: 80})
|
||||
w.Close()
|
||||
if err != nil {
|
||||
Log.Debug("plg_image_transcode::dicom jpeg encoding error '%s'", err.Error())
|
||||
}
|
||||
}()
|
||||
return NewReadCloserFromReader(r), "image/jpeg", nil
|
||||
}
|
||||
return nil, "", ErrNotValid
|
||||
}
|
||||
41
server/plugin/plg_image_transcode/transcode_svg.go
Normal file
41
server/plugin/plg_image_transcode/transcode_svg.go
Normal file
@ -0,0 +1,41 @@
|
||||
package plg_image_transcode
|
||||
|
||||
import (
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"github.com/srwiley/oksvg"
|
||||
"github.com/srwiley/rasterx"
|
||||
"image"
|
||||
"image/png"
|
||||
"io"
|
||||
)
|
||||
|
||||
/*
|
||||
* This bit isn't used because the rendering is very poor and would
|
||||
* generate too many bug reports
|
||||
*/
|
||||
func transcodeSvg(reader io.Reader) (io.ReadCloser, string, error) {
|
||||
icon, err := oksvg.ReadIconStream(reader)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
icon.SetTarget(0, 0, icon.ViewBox.W, icon.ViewBox.H)
|
||||
width := int(icon.ViewBox.W)
|
||||
height := int(icon.ViewBox.H)
|
||||
img := image.NewRGBA(image.Rect(0, 0, width, height))
|
||||
icon.Draw(
|
||||
rasterx.NewDasher(
|
||||
width, height,
|
||||
rasterx.NewScannerGV(width, height, img, img.Bounds()),
|
||||
), 1,
|
||||
)
|
||||
|
||||
r, w := io.Pipe()
|
||||
go func() {
|
||||
err := png.Encode(w, img)
|
||||
w.Close()
|
||||
if err != nil {
|
||||
Log.Debug("plg_image_transcode::svg png encoding error '%s'", err.Error())
|
||||
}
|
||||
}()
|
||||
return NewReadCloserFromReader(r), "image/png", nil
|
||||
}
|
||||
26
server/plugin/plg_image_transcode/transcode_tiff.go
Normal file
26
server/plugin/plg_image_transcode/transcode_tiff.go
Normal file
@ -0,0 +1,26 @@
|
||||
package plg_image_transcode
|
||||
|
||||
import (
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
_ "golang.org/x/image/tiff"
|
||||
"image"
|
||||
"image/jpeg"
|
||||
"io"
|
||||
)
|
||||
|
||||
func transcodeTiff(reader io.Reader) (io.ReadCloser, string, error) {
|
||||
img, _, err := image.Decode(reader)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
r, w := io.Pipe()
|
||||
go func() {
|
||||
err := jpeg.Encode(w, img, &jpeg.Options{Quality: 80})
|
||||
w.Close()
|
||||
if err != nil {
|
||||
Log.Debug("plg_image_transcode::tiff jpeg encoding error '%s'", err.Error())
|
||||
}
|
||||
}()
|
||||
return NewReadCloserFromReader(r), "image/jpeg", nil
|
||||
}
|
||||
Reference in New Issue
Block a user