From 60c3136d8e1f86b32044c31d4bbbe1044d07f69f Mon Sep 17 00:00:00 2001 From: johnerikhalse Date: Tue, 2 May 2023 09:55:07 +0200 Subject: [PATCH] Just for fun --- cmd/aart/aart.go | 164 +++++++++++++++++++++++++++++++++++++++++++++++ cmd/root.go | 2 + go.mod | 11 ++-- go.sum | 18 +++--- 4 files changed, 182 insertions(+), 13 deletions(-) create mode 100644 cmd/aart/aart.go diff --git a/cmd/aart/aart.go b/cmd/aart/aart.go new file mode 100644 index 00000000..8cd49db7 --- /dev/null +++ b/cmd/aart/aart.go @@ -0,0 +1,164 @@ +/* + * Copyright 2023 National Library of Norway. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package aart + +import ( + "bytes" + "errors" + "fmt" + "github.com/nfnt/resize" + "github.com/nlnwa/gowarc" + "github.com/nlnwa/warchaeology/internal/filter" + "github.com/nlnwa/warchaeology/internal/flag" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "image" + "image/color" + _ "image/gif" + _ "image/jpeg" + _ "image/png" + "io" + "os" + "strconv" +) + +type conf struct { + offset int64 + recordNum int + filter *filter.Filter +} + +func NewCommand() *cobra.Command { + c := &conf{} + var cmd = &cobra.Command{ + Use: "aart", + Short: "Show images", + Long: ``, + Hidden: true, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + return errors.New("missing file name") + } + fileName := args[0] + c.offset = viper.GetInt64(flag.Offset) + c.recordNum = viper.GetInt(flag.RecordNum) + + if c.offset < 0 { + c.offset = 0 + } + + viper.Set(flag.MimeType, []string{"image/gif", "image/jpeg", "image/png"}) + c.filter = filter.NewFromViper() + + readFile(c, fileName) + return nil + }, + } + + cmd.Flags().IntP("width", "w", 100, "Width of image") + + return cmd +} + +func readFile(c *conf, fileName string) { + wf, err := gowarc.NewWarcFileReader(fileName, c.offset, gowarc.WithBufferTmpDir(viper.GetString(flag.TmpDir))) + defer func() { _ = wf.Close() }() + if err != nil { + fmt.Printf("Error opening file: %v\n", err) + return + } + + num := 0 + count := 0 + + for { + wr, _, _, err := wf.Next() + if err == io.EOF { + break + } + if err != nil { + _, _ = fmt.Fprintf(os.Stderr, "Error: %v, rec num: %v, Offset %v\n", err.Error(), strconv.Itoa(count), c.offset) + break + } + + if !c.filter.Accept(wr) { + continue + } + + // Find record number + if c.recordNum > 0 && num < c.recordNum { + num++ + continue + } + + if b, ok := wr.Block().(gowarc.HttpResponseBlock); ok { + fmt.Printf("\u001B[2J\u001B[HUrl: %s\n\n", wr.WarcHeader().Get(gowarc.WarcTargetURI)) + r, err := b.PayloadBytes() + if err != nil { + fmt.Printf("Error: %v\n", err) + } + err = display(r, viper.GetInt("width")) + if err != nil { + fmt.Println("Couldn't decode image,\nError:", err.Error()) + continue + } + fmt.Printf("Hit enter to continue\n") + _, _ = fmt.Scanln() + } + } +} + +var asciiChar = "MND8OZ$7I?+=~:,.." + +func asciiArt(img image.Image, w, h int) []byte { + table := []byte(asciiChar) + buffer := new(bytes.Buffer) + for i := 0; i < h; i++ { + for j := 0; j < w; j++ { + g := grayscale(img.At(j, i)) + pos := len(asciiChar) * g / 65536 + _ = buffer.WriteByte(table[pos]) + } + _ = buffer.WriteByte('\n') + } + return buffer.Bytes() +} + +func grayscale(c color.Color) int { + r, g, b, _ := c.RGBA() + return int(0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b)) +} + +func getHeight(img image.Image, w int) (image.Image, int, int) { + sz := img.Bounds() + height := (sz.Max.Y * w * 10) / (sz.Max.X * 16) + img = resize.Resize(uint(w), uint(height), img, resize.Lanczos3) + return img, w, height +} + +func display(r io.Reader, width int) error { + + img, _, err := image.Decode(r) + if err != nil { + return err + } + + finalASCIIArt := asciiArt(getHeight(img, width)) + fmt.Println(string(finalASCIIArt)) + return nil +} diff --git a/cmd/root.go b/cmd/root.go index a8ef5b15..171cb6f4 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -17,6 +17,7 @@ package cmd import ( + "github.com/nlnwa/warchaeology/cmd/aart" "github.com/nlnwa/warchaeology/cmd/cat" "github.com/nlnwa/warchaeology/cmd/console" "github.com/nlnwa/warchaeology/cmd/convert" @@ -63,6 +64,7 @@ func NewCommand() *cobra.Command { cmd.AddCommand(convert.NewCommand()) cmd.AddCommand(dedup.NewCommand()) cmd.AddCommand(completionCmd) + cmd.AddCommand(aart.NewCommand()) config.InitConfig(cmd) return cmd diff --git a/go.mod b/go.mod index 44311d0d..0b03f5b7 100644 --- a/go.mod +++ b/go.mod @@ -7,12 +7,14 @@ require ( github.com/dgraph-io/badger/v3 v3.2103.4 github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f github.com/klauspost/compress v1.15.12 + github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 github.com/nlnwa/gowarc v1.0.1 github.com/nlnwa/whatwg-url v0.1.2 github.com/shirou/gopsutil v2.21.11+incompatible github.com/sirupsen/logrus v1.8.1 github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.6.1 + github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.15.0 github.com/stretchr/testify v1.8.1 ) @@ -50,14 +52,13 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spf13/afero v1.9.3 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/net v0.4.0 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/term v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect + golang.org/x/net v0.5.0 // indirect + golang.org/x/sys v0.4.0 // indirect + golang.org/x/term v0.4.0 // indirect + golang.org/x/text v0.6.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 2bde4d0f..4f3fb4c5 100644 --- a/go.sum +++ b/go.sum @@ -204,6 +204,8 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/nlnwa/gowarc v1.0.1 h1:VZEwS5wlyO3joNvM3tVLkdzhdCcZOVOSG5c3fbWLtUM= github.com/nlnwa/gowarc v1.0.1/go.mod h1:z//s7tRz7zyEz2rlcwSy4aJQdQWlxI3a4Au71YSMW/0= github.com/nlnwa/whatwg-url v0.1.2 h1:BqqsIVG6xv71wOoMAoFDmV6OK6/2sXn7BJdOsTkBl88= @@ -355,8 +357,8 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -416,12 +418,12 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -429,8 +431,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=