Simple way to display image file with HTML forms section - html

I have been playing around with numerous go server snippets trying to figure out how I can display an image file within a HTML file or go HTTP template along with an html forms section. Basically, the biggest problem if I use a go template I cannot show an image along with html and still keep the project size small. It seems the only way to get the template to work is by organizing the code into a "typical go HTML project" which I am trying to avoid.
Is there any easy way (with only a couple files and not creating a "typical go web project file structure") to display HTML with an image inside a go template? I believe the problem below is basically with http handlers. Either I can have a text handler or image handler but not both? I need both so I can have user control from HTML form which image will be displayed.
If anyone can help I would really appreciate it.
R
Joe
--Revised
Sorry about being unclear. I have limited experience with go templates and I have seen many examples where people use go app project file structures that might include directories such as templates, img, etc. These directories are often 10 or more. Then they talk about using routes within apps and other things that I am timid to get into.
I just view what I want to do as much more simple. I have about 70 images. I just want a way where a user can click an html page that displays an image and just provide a number 1,2,3,4 as feedback depending on what image is being displayed.
I imagined that a single go program (1 file) could receive the number and once received change the img on the html page or allow the user to click a next hyperlink or something to bring up the next image and once it is over the program stops.
package main
import (
"fmt"
"html/template"
"log"
"net/http"
//"strings"
func img(w http.ResponseWriter, r *http.Request) {
//http.Handle("/images/", http.StripPrefix("/images/", http.FileServer(http.Dir("images/"))))
fmt.Println("method:", r.Method) //get request method
if r.Method == "GET" {
t, _ := template.ParseFiles("image.gtpl")
t.Execute(w, nil)
} else {
r.ParseForm()
// logic part of log in
fmt.Println("previmage:", r.Form["previmage"])
fmt.Println("nextimage:", r.Form["nextimage"])
}
}
func main() {
//http.HandleFunc("/", sayhelloName) // setting router rule
http.HandleFunc("/login", login)
err := http.ListenAndServe(":9090", nil) // setting listening port
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
<html>
<head>
<title></title>
</head>
<body> //How to Loop Images based on user submit??
<img src="img/question4.png" alt="Cannot load image" style="width: 800px;height: 800px">
<form action="/login" method="post">
Username:<input type="text" name="previmage">
Password:<input type="password" name="nextimage">
<input type="submit" value="Login">
</form>
</body>
</html>

You have your http.Handle call, which registers the handler, inside the handler. That means every time a request comes in, it tries to register the handler again. That's not allowed (hence the error, which says explicitly that you cannot re-register the same route). You should be registering it in the same place you're registering the handler for the template, i.e. in main:
func main() {
http.HandleFunc("/login", login)
// Register handler correctly
// I changed the route to /img/ to match what you're using in your HTML
http.Handle("/img/", http.StripPrefix("/img/", http.FileServer(http.Dir("images/"))))
err := http.ListenAndServe(":9090", nil) // setting listening port
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}

Related

Minio: how to get right link to display image on html

I need to get images from Minio bucket, but I cannot display that image.
I found out that problem was in link. I cannot open it even with browser. So, here is the problem:
GET https://127.0.0.1:9000/myphotos/Jungles.jpeg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=7PAB237ARMGX7RTYHUSL%2F20221202%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20221202T133028Z&X-Amz-Expires=604800&X-Amz-Security-Token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiI3UEFCMjM3QVJNR1g3UlRZSFVTTCIsImV4cCI6MTY3MDAyNzIyNiwicGFyZW50IjoiS2VtYWxBdGRheWV3In0.okb2wO_iLhOlwWeNbixec4R5MRgGw2_KCY_SB9NfuseUI3g9gzTccycbaA6UnZiuuLzbpxPM5tR_hnxa_Y8zWQ&X-Amz-SignedHeaders=host&versionId=null&X-Amz-Signature=281fab24bbe3d651f89c160f5a613512f5e4503f40300ef0008ac94bd9c8f90b
net::ERR_CONNECTION_REFUSED
My code that has been used to upload that file:
package main
import (
"context"
"log"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
)
func main() {
ctx := context.Background()
endpoint := "play.minio.io"
accessKeyId := "KemalAtdayew"
secretAccessKey := "K862008971a!"
useSSL := true
// init minio client object
minioClient, err := minio.New(endpoint, &minio.Options{
Creds: credentials.NewStaticV4(accessKeyId, secretAccessKey, ""),
Secure: useSSL,
})
if err != nil {
log.Fatalln(err)
}
// make a new bucket called myphoto
bucketName := "photobucket"
location := "us-east-1"
err = minioClient.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{Region: location})
if err != nil {
// check to see if we already own this bucket
exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
if errBucketExists == nil && exists {
log.Printf("We already own %s\n", bucketName)
} else {
log.Fatalln(err)
}
} else {
log.Printf("Successfully created %s\n", bucketName)
}
// upload you photos
objectName := "Jungles.jpeg"
filePath := "/minio-1/Jungles.jpeg"
contentType := "image/jpeg"
// upload the zip file FPutObject
info, err := minioClient.FPutObject(ctx, bucketName, objectName, filePath, minio.PutObjectOptions{ContentType: contentType})
if err != nil {
log.Fatalln(err)
}
log.Printf("Successfully uploaded %s of size %d\n", objectName, info.Size)
}
I also gave permission and made it public. Still nothing.
<!DOCTYPE html>
<html>
<head>
<title> Minio </title>
<meta charset="utf-8">
</head>
<body>
<div>
<img src="https://127.0.0.1:9000/myphotos/Jungles.jpeg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=7PAB237ARMGX7RTYHUSL%2F20221202%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20221202T124101Z&X-Amz-Expires=604800&X-Amz-Security-Token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiI3UEFCMjM3QVJNR1g3UlRZSFVTTCIsImV4cCI6MTY3MDAyNzIyNiwicGFyZW50IjoiS2VtYWxBdGRheWV3In0.okb2wO_iLhOlwWeNbixec4R5MRgGw2_KCY_SB9NfuseUI3g9gzTccycbaA6UnZiuuLzbpxPM5tR_hnxa_Y8zWQ&X-Amz-SignedHeaders=host&versionId=null&X-Amz-Signature=5027bd8021a58548ce6be5dead3b622afd951f157a289320ef7dab7701baa7d2" alt="Photo from Minio">
</div>
</body>
</html>
Tried to change html code. Then, found out that it's not html problem.
Tried to share in any other possible way except than, "bucket->click on photo -> click on share"
Link is invalid, but there is no other proper way to get link to that image in bucket.
The path to your local image seems to be strange. Verify if you can open your image manually, and remove all the parameters after the image extension, it should be Forest.jpg
The path to your local image seems to be strange. Verify if you can open your image manually, and remove all the parameters after the image extension, it should be Forest.jpg
If you have Minio running in a container, it is always a mess with 127.0.0.1 or localhost.
Try to generate the link with the minioclient.
mc alias set myminio http://localhost:9000 user password
mc share download myminio/mybucket/object.txt
it will return something like this:
mc share download --recursive minio/testbucket
URL: http://localhost:9000/testbucket/KUBERNETES_AN_ENTERPRISE_GUIDE.pdf
Expire: 7 days 0 hours 0 minutes 0 seconds
Share: http://localhost:9000/testbucket/KUBERNETES_AN_ENTERPRISE_GUIDE.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20221207%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20221207T130336Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=8668da57727f04e7c7e8b15f5d8852fa3801e323cfbc6198384737b77f54cb0b
That link you can open in your Browser.
Note --recursive generate links for all the uploaded files in the bucket.
To get one specific use:
mc share download myminio/testbucket/object.txt.
In production mode as you will use full qualified domain names and not 127.0.0.1 or localhost.
Take a look here about the mc command for generating the link.
https://min.io/docs/minio/linux/reference/minio-mc/mc-share-download.html
If you have a backend and according to your programming language you can also generate links through the api.
Here you find a example for javascript:
https://min.io/docs/minio/linux/developers/javascript/API.html#presignedUrl

What causes browsers to open "Save As" window when downloading dynamic content?

I am experimenting with an idea to stream dynamic data from a web server into a file on the client device. To implement this idea, I am making use of the HTTP Content-Disposition response header and the HTML download attribute. The following is my sample code, where the server is implemented in Go:
HTML:
<a href="download" download>Download</a>
Server:
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
// Handle download request.
http.HandleFunc("/download", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Disposition", "attachment; filename=\"log.txt\"")
w.Write([]byte("first message\n"))
time.Sleep(10 * time.Second)
// The following for-loop takes about 30 seconds to run on my dev machine.
for i := 0; i < 1000000; i++ {
timestamp := time.Now().Unix()
log(timestamp)
w.Write([]byte(fmt.Sprintf("%v\n", timestamp)))
time.Sleep(time.Microsecond)
}
log("done")
})
// Start HTTP server.
if err := http.ListenAndServe(":8080", nil); err != nil {
log(err)
}
}
func log(v ...interface{}) {
fmt.Println(v...)
}
This sample code works in that it successfully downloads all the content from the download handler when clicking on the "Download" link. However, I am observing the following behavior that I am unable to explain:
I have my browser configured to always ask where to save the downloaded files. When running the sample code above, Chrome opens the Save As window only after the 10 second sleep but before the for-loop is complete and in turn the handler function has returned. Why did Chrome not present the Save As window when the "first message" was sent before the 10 second sleep? What is different between the "first message" and the messages being sent in the for-loop that causes the Save As window to only open when the for-loop starts?
Aside: If FileSystemWritableFileStream had greater cross-browser support, I'd use that to stream dynamic server data directly into a file on the client side.
Go's http.ResponseWriter has a default 4KB buffer, defined at the Transport level:
type Transport struct {
// ...
// WriteBufferSize specifies the size of the write buffer used
// when writing to the transport.
// If zero, a default (currently 4KB) is used.
WriteBufferSize int
// ...
}
In some instances, when using standard responses, you can make use the Flush method by using type assertion with the http.Flusher interface to send the bytes right away:
if f, ok := w.(http.Flusher); ok {
f.Flush()
}
To have Firefox open the Save As window immediately after "first message" is sent, Ricardo Souza's answer appears to be all that's needed. To have Chrome do the same, the response's Content-Type header also needs to be set to anything other than the default text/plain (thanks to this SO answer). Example:
w.Header().Set("Content-Type", "application/octet-stream; charset=utf-8")

Swift - Switch multiple (x)html files in the same webview

I have one webview in my view controller that I want to use as a reader. How can I switch between multiple (x)html files in this webview? I retrieve them one by one with the following code:
apiClient.getData(forFile: file) { (data, error) in
if let error = error {
//show error
return
}
if let data = data {
self.data = data
self.webView.load(data, mimeType: mimeType, textEncodingName: "utf-8", baseURL: URL(string: "")!)
}
}
Right now When a user scrolls (horizontal) through the pages of an epub and transitions from one file to another, there is a short loading time (because it is retrieving the next xhtml from the server).
Right now, it is a jarring experience, preventing the user from scrolling forward. When the next file is loaded, the page jumps to the new one.

UIMarkupTextPrintFormatter never renders base64 images

Im creating a pdf file out of html content in swift 3.0:
/**
*
*/
func exportHtmlContentToPDF(HTMLContent: String, filePath: String) {
// let webView = UIWebView(frame: CGRect(x: 0, y: 0, width: 694, height: 603));
// webView.loadHTMLString(HTMLContent, baseURL: nil);
let pdfPrinter = PDFPrinter();
let printFormatter = UIMarkupTextPrintFormatter(markupText: HTMLContent);
// let printFormatter = webView.viewPrintFormatter();
pdfPrinter.addPrintFormatter(printFormatter, startingAtPageAt: 0);
let pdfData = self.drawPDFUsingPrintPageRenderer(printPageRenderer: pdfPrinter);
pdfData?.write(toFile: filePath, atomically: true);
}
/**
*
*/
func drawPDFUsingPrintPageRenderer(printPageRenderer: UIPrintPageRenderer) -> NSData! {
let data = NSMutableData();
UIGraphicsBeginPDFContextToData(data, CGRect.zero, nil);
printPageRenderer.prepare(forDrawingPages: NSMakeRange(0, printPageRenderer.numberOfPages));
let bounds = UIGraphicsGetPDFContextBounds();
for i in 0...(printPageRenderer.numberOfPages - 1) {
UIGraphicsBeginPDFPage();
printPageRenderer.drawPage(at: i, in: bounds);
}
UIGraphicsEndPDFContext();
return data;
}
Everything is rendered fine except my base64 encoded images. The HTML content itself in a webview or inside safari or chrome browser is presented correctly and is showing all images correctly. But the images are never rendered into the pdf.
Why are the images not rendered and how can I get them to be rendered?
This happens because WebKit first parses the HTML into a DOM, and renders content on multiple event loop cycles. You therefore need to wait for not just the page DOM to be ready but for the resource loading to be complete. As you also suggest, you need to refactor your code such that the webview gets loaded first, and you only then export its contents.
To determine the correct time to fire the export, you can observe for the state of the DOM document in the web view. There are multiple ways to do this, but the most readable option I find is a port of an answer to a related Objective-C question: in your UIWebViewDelegate implementation, implement webViewDidFinishLoad in the following way to monitor document.readyState:
func webViewDidFinishLoad(_ webView: UIWebView) {
guard let readyState = webView.stringByEvaluatingJavaScript(from: "document.readyState"),
readyState == "complete" else
{
// document not yet parsed, or resources not yet loaded.
return
}
// This is the last webViewDidFinishLoad call --> export.
//
// There is a problem with this method if you have JS code loading more content:
// in that case -webViewDidFinishLoad can get called again still after document.readyState has already been in state 'complete' once or more.
self.exportHtmlContentToPDF(…)
}
I found the solution!
The export to PDF happens before the rendering process is finished. If you put in a very small picture it is showing up in the PDF. If the picture is too big the rendering process takes too much time but the PDF export isnt waiting for the rendering to finish.
So what I did to make it work is the following:
Before I export to PDF I show the Result of the HTML in a WebView. The WebView is rendering everything correctly and now when I press on export to PDF the PDF is showing up correctly with all images inside.
So I guess this is a huge lag that there is no way to tell the PDF Exporter to wait for the rendering process to finish.

same code but different results using gin + go-template

Basic information
Go version: go1.4.2 darwin/amd64
Operating System: Mac OS X 10.10.5
I'm working on a small Web project written based on go and gin. Here is my golang code. After running go run test.go we have a web server, which is listening on 8089.
Golang test.go
package main
import "github.com/gin-gonic/gin"
import "net/http"
func main() {
router := gin.Default()
router.LoadHTMLGlob("templates/*")
router.GET("/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{
"scheme": "http",
"domain": "meican.loc",
})
})
router.Run(":8089") // listen and serve on 0.0.0.0:8089
}
The html code generated in back-end should contain a template used by front-end javascript engine (Let's say Angular.js).
So the template code is in script tag, just like this:
Part of templates/index.html
<script type="text/template" charset="utf-8">
<div data="{{.scheme}}://{{.domain}}/qr"></div>
<div data="{{.scheme}}://{{.domain}}/qr"></div> <!-- problem here -->
</script>
When {{.domain}} is used at the second time, I got different result. I refreshed the browser and checked out the source code. Then I got this:
Browser source code result
<script type="text/template" charset="utf-8">
<div data="http://meican.loc/qr"></div>
<div data="http://"meican.loc"/qr"></div> <!-- problems here -->
</script>
The second div has 2 extra double quotes.
Why this happens? And how to resolve this problem?
This is a bug in Go, and has been slated to be fixed in 1.7 as of March 2016 (Also partially addressed in 1.6)