switch image code to webs
This commit is contained in:
parent
d121408464
commit
af849f4371
|
@ -23,7 +23,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html"
|
"html"
|
||||||
"image"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -33,6 +32,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"humungus.tedunangst.com/r/webs/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewJunk() map[string]interface{} {
|
func NewJunk() map[string]interface{} {
|
||||||
|
@ -222,13 +223,13 @@ func savedonk(url string, name, media string) *Donk {
|
||||||
|
|
||||||
data := buf.Bytes()
|
data := buf.Bytes()
|
||||||
if strings.HasPrefix(media, "image") {
|
if strings.HasPrefix(media, "image") {
|
||||||
img, format, err := image.Decode(&buf)
|
img, err := image.Vacuum(&buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("unable to decode image: %s", err)
|
log.Printf("unable to decode image: %s", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
data, format, err = vacuumwrap(img, format)
|
data = img.Data
|
||||||
media = "image/" + format
|
media = "image/" + img.Format
|
||||||
}
|
}
|
||||||
res, err := stmtSaveFile.Exec(xid, name, url, media, data)
|
res, err := stmtSaveFile.Exec(xid, name, url, media, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -6,5 +6,5 @@ require (
|
||||||
golang.org/x/crypto v0.0.0-20190424203555-c05e17bb3b2d
|
golang.org/x/crypto v0.0.0-20190424203555-c05e17bb3b2d
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3
|
||||||
humungus.tedunangst.com/r/go-sqlite3 v1.1.2
|
humungus.tedunangst.com/r/go-sqlite3 v1.1.2
|
||||||
humungus.tedunangst.com/r/webs v0.2.0
|
humungus.tedunangst.com/r/webs v0.3.0
|
||||||
)
|
)
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -12,5 +12,5 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
humungus.tedunangst.com/r/go-sqlite3 v1.1.2 h1:bRAXNRZ4VNFRFhhG4tdudK4Lv4ktHQAHEppKlDANUFg=
|
humungus.tedunangst.com/r/go-sqlite3 v1.1.2 h1:bRAXNRZ4VNFRFhhG4tdudK4Lv4ktHQAHEppKlDANUFg=
|
||||||
humungus.tedunangst.com/r/go-sqlite3 v1.1.2/go.mod h1:FtEEmQM7U2Ey1TuEEOyY1BmphTZnmiEjPsNLEAkpf/M=
|
humungus.tedunangst.com/r/go-sqlite3 v1.1.2/go.mod h1:FtEEmQM7U2Ey1TuEEOyY1BmphTZnmiEjPsNLEAkpf/M=
|
||||||
humungus.tedunangst.com/r/webs v0.2.0 h1:K0PJK4ZFNB+B0vGbs6huY5br35Z9xR4T6XpcFHmwXgQ=
|
humungus.tedunangst.com/r/webs v0.3.0 h1:Igx471E1Rabh5BIkVJw9N48xGNEHENx05r/7lOBJRUs=
|
||||||
humungus.tedunangst.com/r/webs v0.2.0/go.mod h1:6yLLDXBaE4pKURa/3/bxoQPod37uAqc/Kq8J0IopWW0=
|
humungus.tedunangst.com/r/webs v0.3.0/go.mod h1:6yLLDXBaE4pKURa/3/bxoQPod37uAqc/Kq8J0IopWW0=
|
||||||
|
|
11
honk.go
11
honk.go
|
@ -23,7 +23,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"html"
|
"html"
|
||||||
"html/template"
|
"html/template"
|
||||||
"image"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
notrand "math/rand"
|
notrand "math/rand"
|
||||||
|
@ -36,6 +35,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"humungus.tedunangst.com/r/webs/image"
|
||||||
"humungus.tedunangst.com/r/webs/login"
|
"humungus.tedunangst.com/r/webs/login"
|
||||||
"humungus.tedunangst.com/r/webs/templates"
|
"humungus.tedunangst.com/r/webs/templates"
|
||||||
)
|
)
|
||||||
|
@ -883,13 +883,10 @@ func savehonk(w http.ResponseWriter, r *http.Request) {
|
||||||
data := buf.Bytes()
|
data := buf.Bytes()
|
||||||
xid := xfiltrate()
|
xid := xfiltrate()
|
||||||
var media, name string
|
var media, name string
|
||||||
img, format, err := image.Decode(&buf)
|
img, err := image.Vacuum(&buf)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
data, format, err = vacuumwrap(img, format)
|
data = img.Data
|
||||||
if err != nil {
|
format := img.Format
|
||||||
log.Printf("can't vacuum image: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
media = "image/" + format
|
media = "image/" + format
|
||||||
if format == "jpeg" {
|
if format == "jpeg" {
|
||||||
format = "jpg"
|
format = "jpg"
|
||||||
|
|
148
image.go
148
image.go
|
@ -1,148 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2019 Ted Unangst <tedu@tedunangst.com>
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, and distribute this software for any
|
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
|
||||||
// copyright notice and this permission notice appear in all copies.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"image"
|
|
||||||
"image/jpeg"
|
|
||||||
"image/png"
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
func lineate(s uint8) float64 {
|
|
||||||
x := float64(s)
|
|
||||||
x /= 255.0
|
|
||||||
if x < 0.04045 {
|
|
||||||
x /= 12.92
|
|
||||||
} else {
|
|
||||||
x += 0.055
|
|
||||||
x /= 1.055
|
|
||||||
x = math.Pow(x, 2.4)
|
|
||||||
}
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
func delineate(x float64) uint8 {
|
|
||||||
if x > 0.0031308 {
|
|
||||||
x = math.Pow(x, 1/2.4)
|
|
||||||
x *= 1.055
|
|
||||||
x -= 0.055
|
|
||||||
} else {
|
|
||||||
x *= 12.92
|
|
||||||
}
|
|
||||||
x *= 255.0
|
|
||||||
return uint8(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func blend(d []byte, s1, s2, s3, s4 int) byte {
|
|
||||||
l1 := lineate(d[s1])
|
|
||||||
l2 := lineate(d[s2])
|
|
||||||
l3 := lineate(d[s3])
|
|
||||||
l4 := lineate(d[s4])
|
|
||||||
return delineate((l1 + l2 + l3 + l4) / 4.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func squish(d []byte, s1, s2, s3, s4 int) byte {
|
|
||||||
return uint8((uint32(d[s1]) + uint32(d[s2]) + uint32(d[s3]) + uint32(d[s4])) / 4)
|
|
||||||
}
|
|
||||||
|
|
||||||
func vacuumwrap(img image.Image, format string) ([]byte, string, error) {
|
|
||||||
maxdimension := 2048
|
|
||||||
for img.Bounds().Max.X > maxdimension || img.Bounds().Max.Y > maxdimension {
|
|
||||||
switch oldimg := img.(type) {
|
|
||||||
case *image.NRGBA:
|
|
||||||
w, h := oldimg.Rect.Max.X/2, oldimg.Rect.Max.Y/2
|
|
||||||
newimg := image.NewNRGBA(image.Rectangle{Max: image.Point{X: w, Y: h}})
|
|
||||||
for j := 0; j < h; j++ {
|
|
||||||
for i := 0; i < w; i++ {
|
|
||||||
p := newimg.Stride*j + i*4
|
|
||||||
q1 := oldimg.Stride*(j*2+0) + i*4*2
|
|
||||||
q2 := oldimg.Stride*(j*2+1) + i*4*2
|
|
||||||
newimg.Pix[p+0] = blend(oldimg.Pix, q1+0, q1+4, q2+0, q2+4)
|
|
||||||
newimg.Pix[p+1] = blend(oldimg.Pix, q1+1, q1+5, q2+1, q2+5)
|
|
||||||
newimg.Pix[p+2] = blend(oldimg.Pix, q1+2, q1+6, q2+2, q2+6)
|
|
||||||
newimg.Pix[p+3] = squish(oldimg.Pix, q1+3, q1+7, q2+3, q2+7)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
img = newimg
|
|
||||||
case *image.YCbCr:
|
|
||||||
w, h := oldimg.Rect.Max.X/2, oldimg.Rect.Max.Y/2
|
|
||||||
newimg := image.NewYCbCr(image.Rectangle{Max: image.Point{X: w, Y: h}},
|
|
||||||
oldimg.SubsampleRatio)
|
|
||||||
for j := 0; j < h; j++ {
|
|
||||||
for i := 0; i < w; i++ {
|
|
||||||
p := newimg.YStride*j + i
|
|
||||||
q1 := oldimg.YStride*(j*2+0) + i*2
|
|
||||||
q2 := oldimg.YStride*(j*2+1) + i*2
|
|
||||||
newimg.Y[p+0] = blend(oldimg.Y, q1+0, q1+1, q2+0, q2+1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch newimg.SubsampleRatio {
|
|
||||||
case image.YCbCrSubsampleRatio444:
|
|
||||||
w, h = w, h
|
|
||||||
case image.YCbCrSubsampleRatio422:
|
|
||||||
w, h = w/2, h
|
|
||||||
case image.YCbCrSubsampleRatio420:
|
|
||||||
w, h = w/2, h/2
|
|
||||||
case image.YCbCrSubsampleRatio440:
|
|
||||||
w, h = w, h/2
|
|
||||||
case image.YCbCrSubsampleRatio411:
|
|
||||||
w, h = w/4, h
|
|
||||||
case image.YCbCrSubsampleRatio410:
|
|
||||||
w, h = w/4, h/2
|
|
||||||
}
|
|
||||||
for j := 0; j < h; j++ {
|
|
||||||
for i := 0; i < w; i++ {
|
|
||||||
p := newimg.CStride*j + i
|
|
||||||
q1 := oldimg.CStride*(j*2+0) + i*2
|
|
||||||
q2 := oldimg.CStride*(j*2+1) + i*2
|
|
||||||
newimg.Cb[p+0] = blend(oldimg.Cb, q1+0, q1+1, q2+0, q2+1)
|
|
||||||
newimg.Cr[p+0] = blend(oldimg.Cr, q1+0, q1+1, q2+0, q2+1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
img = newimg
|
|
||||||
default:
|
|
||||||
return nil, "", fmt.Errorf("can't support image format")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
maxsize := 512 * 1024
|
|
||||||
quality := 80
|
|
||||||
var buf bytes.Buffer
|
|
||||||
for {
|
|
||||||
switch format {
|
|
||||||
case "png":
|
|
||||||
png.Encode(&buf, img)
|
|
||||||
case "jpeg":
|
|
||||||
jpeg.Encode(&buf, img, &jpeg.Options{Quality: quality})
|
|
||||||
default:
|
|
||||||
return nil, "", fmt.Errorf("can't encode format: %s", format)
|
|
||||||
}
|
|
||||||
if buf.Len() > maxsize && quality > 30 {
|
|
||||||
switch format {
|
|
||||||
case "png":
|
|
||||||
format = "jpeg"
|
|
||||||
case "jpeg":
|
|
||||||
quality -= 10
|
|
||||||
}
|
|
||||||
buf.Reset()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return buf.Bytes(), format, nil
|
|
||||||
}
|
|
Loading…
Reference in New Issue