关于在fyne中canvas的图像加载问题fyne.URI的定义

问题:

在学习golang的fyne时,我发现网上没有合适的教程,要么直接是复制官网的,要么直接不知道在写什么。
在官网学习到canvas的Image时,我只是想了解每一种方式的不同,但是前面几种在本地资源中加载图像都没有问题,但是在使用从url加载图像时出现了问题,找不到uri类型的定义方法。
我找遍了网上的博客,我最后评论一句:
“相似的人太多,以至于根本没有一个真正的人”

解决方法

在之前的URI在fyne根目录下,但是在v2版本中被移植到了其它包

"fyne.io/fyne/v2/storage" //在repository中实现URi类型

目录结构如下
在这里插入图片描述

在这里插入图片描述
其中URI.go这些文件都是在定义uri类型的接口或者方法,真正的定义位置在下面这里
在这里插入图片描述

URI结构体的定义

这就是真正被定义的位置,URI的具体类型和net/url是相似的

package repository

import (
	"bufio"
	"mime"
	"path/filepath"
	"strings"
	"unicode/utf8"

	"fyne.io/fyne/v2"
)

// Declare conformance with fyne.URI interface.
var _ fyne.URI = &uri{}

type uri struct {
	scheme    string
	authority string
	path      string
	query     string
	fragment  string
}

URI的基础方法

func (u *uri) Extension() string {
	return filepath.Ext(u.path)
}

func (u *uri) Name() string {
	return filepath.Base(u.path)
}

func (u *uri) MimeType() string {

	mimeTypeFull := mime.TypeByExtension(u.Extension())
	if mimeTypeFull == "" {
		mimeTypeFull = "text/plain"

		repo, err := ForURI(u)
		if err != nil {
			return "application/octet-stream"
		}

		readCloser, err := repo.Reader(u)
		if err == nil {
			defer readCloser.Close()
			scanner := bufio.NewScanner(readCloser)
			if scanner.Scan() && !utf8.Valid(scanner.Bytes()) {
				mimeTypeFull = "application/octet-stream"
			}
		}
	}

	return strings.Split(mimeTypeFull, ";")[0]
}

func (u *uri) Scheme() string {
	return u.scheme
}

func (u *uri) String() string {
	// NOTE: this string reconstruction is mandated by IETF RFC3986,
	// section 5.3, pp. 35.

	s := u.scheme + "://" + u.authority + u.path
	if len(u.query) > 0 {
		s += "?" + u.query
	}
	if len(u.fragment) > 0 {
		s += "#" + u.fragment
	}
	return s
}

func (u *uri) Authority() string {
	return u.authority
}

func (u *uri) Path() string {
	return u.path
}

func (u *uri) Query() string {
	return u.query
}

func (u *uri) Fragment() string {
	return u.fragment
}

如何使用函数创建一个fyne.URI类型

package repository

import (
	"errors"
	"path/filepath"
	"runtime"
	"strings"

	uriParser "github.com/fredbi/uri"

	"fyne.io/fyne/v2"
)

// NewFileURI implements the back-end logic to storage.NewFileURI, which you
// should use instead. This is only here because other functions in repository
// need to call it, and it prevents a circular import.
//
// Since: 2.0
func NewFileURI(path string) fyne.URI {
	// URIs are supposed to use forward slashes. On Windows, it
	// should be OK to use the platform native filepath with UNIX
	// or NT style paths, with / or \, but when we reconstruct
	// the URI, we want to have / only.
	if runtime.GOOS == "windows" {
		// seems that sometimes we end up with
		// double-backslashes
		path = filepath.ToSlash(path)
	}

	return &uri{
		scheme: "file",
		path:   path,
	}
}

// ParseURI implements the back-end logic for storage.ParseURI, which you
// should use instead. This is only here because other functions in repository
// need to call it, and it prevents a circular import.
//
// Since: 2.0
func ParseURI(s string) (fyne.URI, error) {
	// Extract the scheme.
	colonIndex := strings.IndexByte(s, ':')
	if colonIndex <= 0 {
		return nil, errors.New("invalid URI, scheme must be present")
	}

	scheme := strings.ToLower(s[:colonIndex])

	if scheme == "file" {
		// Does this really deserve to be special? In principle, the
		// purpose of this check is to pass it to NewFileURI, which
		// allows platform path seps in the URI (against the RFC, but
		// easier for people building URIs naively on Windows). Maybe
		// we should punt this to whoever generated the URI in the
		// first place?

		if len(s) <= 7 {
			return nil, errors.New("not a valid URI")
		}
		path := s[5:] // everything after file:
		if len(path) > 2 && path[:2] == "//" {
			path = path[2:]
		}

		// Windows files can break authority checks, so just return the parsed file URI
		return NewFileURI(path), nil
	}

	repo, err := ForScheme(scheme)
	if err == nil {
		// If the repository registered for this scheme implements a parser
		if c, ok := repo.(CustomURIRepository); ok {
			return c.ParseURI(s)
		}
	}

	// There was no repository registered, or it did not provide a parser

	l, err := uriParser.Parse(s)
	if err != nil {
		return nil, err
	}

	authority := ""

	if userInfo := l.Authority().UserInfo(); len(userInfo) > 0 {
		authority += userInfo + "@"
	}

	authority += l.Authority().Host()

	if port := l.Authority().Port(); len(port) > 0 {
		authority += ":" + port
	}

	return &uri{
		scheme:    scheme,
		authority: authority,
		path:      l.Authority().Path(),
		query:     l.Query().Encode(),
		fragment:  l.Fragment(),
	}, nil
}

NewFileURI 使用path字符串创建(本地系统资源使用)

// NewFileURI implements the back-end logic to storage.NewFileURI, which you
// should use instead. This is only here because other functions in repository
// need to call it, and it prevents a circular import.

使用注意点:

URI 应该使用正斜杠。在Windows上,它
应该可以与 UNIX 一起使用平台本机文件路径
或 NT 样式路径,带有 或
原理:golang实现的是Unix

示例

package main

import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/canvas"
)

func main() {
	myApp := app.New()
	w := myApp.NewWindow("Image")
	image := canvas.NewImageFromFile("D:\\Goland\\GinWeb\\DesktopAPP\\day03\\dome06\\纳西妲1.png") //从本地资源加载

	w.SetContent(image)
	w.Resize(fyne.NewSize(500, 500))
	w.ShowAndRun()
}

目录:
纳西妲
运行结果:
在这里插入图片描述

ParseURI 通过解析url字符串创建URI类型(请求主要用于web)

注意:

url字符串不能有任何错误,否则就会出现请求错误,并且是这个方法需要进行错误处理,该方法相当于浏览器,不会下载图片,只会展示,不会占用大量的内存

示例

package main

import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/canvas"
	"fyne.io/fyne/v2/storage"
	"log"
)

func main() {
	myApp := app.New()
	w := myApp.NewWindow("Image")
	urls, err := storage.ParseURI("https://img.vm.laomishuo.com/image/2022/09/202209071038022.jpg")//解析url字符串
	if err != nil {
		log.Fatal(err)
		return
	}
	image := canvas.NewImageFromURI(urls)
	w.SetContent(image)
	w.Resize(fyne.NewSize(500, 500))
	w.ShowAndRun()
}

运行结果:
在这里插入图片描述

ParseURI 用于本地文件

ParseURI 也可以用于本地文件,但是不建议,因为这样效率还不如直接使用第一种。
看一下实现就知道了

if scheme == "file" {
		// Does this really deserve to be special? In principle, the
		// purpose of this check is to pass it to NewFileURI, which
		// allows platform path seps in the URI (against the RFC, but
		// easier for people building URIs naively on Windows). Maybe
		// we should punt this to whoever generated the URI in the
		// first place?

		if len(s) <= 7 {
			return nil, errors.New("not a valid URI")
		}
		path := s[5:] // everything after file:
		if len(path) > 2 && path[:2] == "//" {
			path = path[2:]
		}

		// Windows files can break authority checks, so just return the parsed file URI
		return NewFileURI(path), nil
	}

如果你的协议头是“file”,那么最后调用的方法其实还是NewFileURI方法,这样效率低,而且浪费时间

剩下的方法

剩下其实没必要了,这两种就已经足够了,因为剩下的方法底层实现和这两种挂钩了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜未至

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值