Skip to content
This repository has been archived by the owner on Apr 7, 2022. It is now read-only.

Commit

Permalink
Merge pull request #1 from Ink-33/master
Browse files Browse the repository at this point in the history
添加对Markdown文件的渲染支持
  • Loading branch information
jujusharp authored Jul 14, 2020
2 parents dee556e + c5681b3 commit b5b8a39
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 37 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ _cgo_gotypes.go
_cgo_export.*

_testmain.go

_main.backup.go
*.exe
*.test
*.prof
html2image
30 changes: 21 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,50 @@
# html2image
a golang wrapper to reander html to image
a golang wrapper to reander html, markdown to image

## Usage

### directly render image

1. render png

http://127.0.0.1:8080/to/img.png?url=http://www.google.com
[http://127.0.0.1:10000/v1/html2img/to/img.png?url=http://www.google.com](http://127.0.0.1:10000/v1/html2img/to/img.png?url=http://www.google.com)

2. render jpg

http://127.0.0.1:8080/to/img.jpg?url=http://www.google.com
[http://127.0.0.1:10000/v1/html2img/to/img.jpg?url=http://www.google.com](http://127.0.0.1:10000/v1/html2img/to/img.jpg?url=http://www.google.com)

3. render png (markdown only)

[http://127.0.0.1:10000/v1/md2img/to/img.png?url=https://github.com/Ink-33/html2image/raw/master/README.md](http://127.0.0.1:10000/v1/md2img/to/img.png?url=https://github.com/Ink-33/html2image/raw/master/README.md)

4. render jpg (markdown only)

[http://127.0.0.1:10000/v1/md2img/to/img.jpg?url=https://github.com/Ink-33/html2image/raw/master/README.md](http://127.0.0.1:10000/v1/md2img/to/img.jpg?url=https://github.com/Ink-33/html2image/raw/master/README.md)

**Notice**:
This program will analyze _markdown_ (when `url` end with `.md`). If you don't want to render a _markdown_ file, please add the `nomd=true` parameter to the url.

### render image and return image url info

1. render image and return json

http://127.0.0.1:8080/api/v1/to/img.json?url=http://www.google.com&format=jpg
[http://127.0.0.1:10000/v1/html2img/to/img.json?url=http://www.google.com&format=jpg](http://127.0.0.1:10000/v1/html2img/to/img.json?url=http://www.google.com&format=jpg)

2. show image url from the json result

http://127.0.0.1:8080/show/img/{your image url}
[http://127.0.0.1:10000/v1/html2img/show/img/](http://127.0.0.1:10000/v1/html2img/show/img/){your image url}

## More Params In Url
```shell
html: the html content to render, if url has set, this param will ignore
md: the markdown content to render, if url has set,
this param will ignore (not support yet)
nomd: ingore markdown url
width: the html page width
height: the html page height
quality: the image quality

```
## Changelog
2020/04/23 Add markdown render support.
94 changes: 73 additions & 21 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,84 @@ import (
"errors"
"flag"
"fmt"
"github.com/unrolled/render" // or "gopkg.in/unrolled/render.v1"
"gopkg.in/russross/blackfriday.v2"
"io/ioutil"
"log"
"net/http"
"os"
"strconv"
"strings"
"time"
"github.com/unrolled/render" // or "gopkg.in/unrolled/render.v1"
)

type ImageRender struct {
BinaryPath *string
}

func md2html(url string) string {
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
return "<p>Render Fail. Reason: Can not get content. </p>"
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
return "<p>Render Fail. Reason: Can not read body. </p>"
}
return string(blackfriday.Run(body))
}

func (r *ImageRender) BuildImageOptions(req *http.Request, format string) (ImageOptions, error) {
path := req.URL.Path
url := req.Form.Get("url")

reqIP := req.Header.Get("X-Forwarded-For")
var html string
if len(url) == 0 {
html = req.Form.Get("html")

if len(html) == 0 {
return ImageOptions{}, errors.New("url can't be null")
if !strings.HasPrefix(path, "/v1/md2img/") {
if len(url) == 0 {
html = req.Form.Get("html")

if len(html) == 0 {
return ImageOptions{}, errors.New("url can't be null")
} else {
url = "-"
log.Println("render for:", html, " RemoteIP:", reqIP)
}
} else if strings.HasSuffix(url, ".md") {
if req.Form.Get("nomd") != "true" {
html = "<meta charset=\"utf-8\">" + md2html(url)
log.Println("render markdown for:", url, " RemoteIP:", reqIP)
url = "-"
} else {
html = ""
log.Println("render for:", url, " RemoteIP:", reqIP)
}
} else {
url = "-"
log.Println("render for: ", html)
html = ""
log.Println("render for:", url, " RemoteIP:", reqIP)
}
} else {
html = ""
log.Println("render for: ", url)
if strings.HasSuffix(url, ".md") {
if req.Form.Get("nomd") != "true" {
html = "<meta charset=\"utf-8\">" + md2html(url)
log.Println("render markdown for:", url, " RemoteIP:", reqIP)
url = "-"
} else {
log.Println("Prevent \"nomd\" in force markdown mode. url:", url, " RemoteIP:", reqIP)
return ImageOptions{}, errors.New("\"nomd\" cannot be true in force markdown mode")

}
} else {
log.Println("Prevent rendering ", url, "in force markdown mode.", " RemoteIP:", reqIP)
return ImageOptions{}, errors.New("url must be end with \".md\"in force markdown mode")
}
}

c := ImageOptions{BinaryPath: *r.BinaryPath,
Input: url, Html: html, Format: format}
Input: url, HTML: html, Format: format}

width, err := strconv.Atoi(req.Form.Get("width"))
if err == nil {
Expand Down Expand Up @@ -76,7 +122,7 @@ func (r *ImageRender) RenderBytes(w http.ResponseWriter, req *http.Request, form
w.Write(out)
}

func (r *ImageRender) RenderJson(httpRender *render.Render, w http.ResponseWriter,
func (r *ImageRender) RenderJSON(httpRender *render.Render, w http.ResponseWriter,
req *http.Request, imgRootDir *string) {
err := req.ParseForm()
if err != nil {
Expand All @@ -103,7 +149,7 @@ func (r *ImageRender) RenderJson(httpRender *render.Render, w http.ResponseWrite

today := time.Now().Format("06/01/02/")
os.MkdirAll(*imgRootDir+today, 0755)
imgPath := today + contentToMd5(c.Input+c.Html) + "." + format
imgPath := today + contentToMd5(c.Input+c.HTML) + "." + format
c.Output = *imgRootDir + imgPath
log.Println("generate file path:", c.Output)
if !checkFileIsExist(c.Output) {
Expand Down Expand Up @@ -136,29 +182,35 @@ func contentToMd5(content string) string {
func main() {
binPath := flag.String("path", "/usr/local/bin/wkhtmltoimage", "wkhtmltoimage bin path")
imgRootDir := flag.String("img.dir", "./tmp/", "generated image local dir")
port := flag.String("web.port", "8080", "web server port")
port := flag.String("web.port", "10000", "web server port")
flag.Parse()
imgRender := ImageRender{}
imgRender.BinaryPath = binPath
r := render.New()
mux := http.NewServeMux()
staticHandler := http.FileServer(http.Dir(*imgRootDir))

mux.HandleFunc("/to/img.png", func(w http.ResponseWriter, req *http.Request) {
log.Println("Start.")
mux.HandleFunc("/v1/html2img/to/img.png", func(w http.ResponseWriter, req *http.Request) {
imgRender.RenderBytes(w, req, "png")
})
mux.HandleFunc("/to/img.jpg", func(w http.ResponseWriter, req *http.Request) {
mux.HandleFunc("/v1/html2img/to/img.jpg", func(w http.ResponseWriter, req *http.Request) {
imgRender.RenderBytes(w, req, "jpg")
})
mux.HandleFunc("/show/img/", func(w http.ResponseWriter, req *http.Request) {
mux.HandleFunc("/v1/html2img/show/img/", func(w http.ResponseWriter, req *http.Request) {
req.URL.Path = req.URL.Path[9:]
staticHandler.ServeHTTP(w, req)
})
mux.HandleFunc("/api/v1/to/img.json", func(w http.ResponseWriter, req *http.Request) {
imgRender.RenderJson(r, w, req, imgRootDir)
mux.HandleFunc("/v1/html2img/to/img.json", func(w http.ResponseWriter, req *http.Request) {
imgRender.RenderJSON(r, w, req, imgRootDir)
})
mux.HandleFunc("/v1/md2img/to/img.png", func(w http.ResponseWriter, req *http.Request) {
imgRender.RenderBytes(w, req, "png")
})
mux.HandleFunc("/v1/md2img/to/img.jpg", func(w http.ResponseWriter, req *http.Request) {
imgRender.RenderBytes(w, req, "jpg")
})
if len(*port) == 0 {
*port = "8080"
*port = "10000"
}
http.ListenAndServe(":"+*port, mux)
}
12 changes: 6 additions & 6 deletions wkhtmltoimage.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type ImageOptions struct {
BinaryPath string
// Input is the content to turn into an image. REQUIRED
//
// Can be a url (http://example.com), a local file (/tmp/example.html), or html as a string (send "-" and set the Html value)
// Can be a url (http://example.com), a local file (/tmp/example.html), or html as a string (send "-" and set the HTML value)
Input string
// Format is the type of image to generate
//
Expand All @@ -46,10 +46,10 @@ type ImageOptions struct {
CropW int
// Crop-h determines the final image crop height
CropH int
// Html is a string of html to render into and image.
// HTML is a string of html to render into and image.
//
// Only needed to be set if Input is set to "-"
Html string
HTML string
// Output controls how to save or return the image.
//
// Leave nil to return a []byte of the image. Set to a path (/tmp/example.png) to save as a file.
Expand All @@ -70,8 +70,8 @@ func GenerateImage(options *ImageOptions) ([]byte, error) {

cmd := exec.Command(options.BinaryPath, arr...)

if options.Html != "" {
cmd.Stdin = strings.NewReader(options.Html)
if options.HTML != "" {
cmd.Stdin = strings.NewReader(options.HTML)
}

output, err := cmd.CombinedOutput()
Expand Down Expand Up @@ -147,7 +147,7 @@ func buildParams(options *ImageOptions) ([]string, error) {
// url and output come last
if options.Input != "-" {
// make sure we dont pass stdin if we aren't expecting it
options.Html = ""
options.HTML = ""
}

a = append(a, options.Input)
Expand Down

0 comments on commit b5b8a39

Please sign in to comment.