Imkaer 是一款用来设计封面的工具,比如你可以为你的博客、视频、公众号等设计你自己喜欢的封面。
🌟 第一步:创建一个.env.local
文件,更改 .env.local
中的 VITE_PUBLIC_UNSPLASH_API_KEY
VITE_PUBLIC_UNSPLASH_API_KEY = your_unsplash_api_key
https://unsplash.com/documentation
💥 第二步:更改 .env.local
中的 VITE_PUBLIC_HUGGINGFACE_API_KEY
VITE_PUBLIC_HUGGINGFACE_API_KEY = your_huggingface_api_key
https://huggingface.co/settings/tokens
🌈 第三步:克隆项目
git clone [email protected]:slince-zero/IMaker.git
cd img-maker
npm i
npm run dev
打开 http://localhost:5173 查看效果
https://github.com/gezhaoyou/picprose
- 通过 AI 生成图片 🔥
GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
通过 createContext 创建一个 contextProvider 就可以在任意组件里面传递数据,而且很灵活,可以直接在跟组件里面用 contextProvider 来包裹根组件。 也可以用它包裹任意你想传递数据的组件当中。
<label>
<input
type='file'
onChange={handleUploadImage}
className='hidden'
/>
<Button
variant='flat'
isIconOnly
as='span'>
<UploadLogo />
</Button>
</label>
这里的 as=span
是因为有一些默认行为,会影响事件上传功能的执行,所以这里用 as='span'
来修复这个问题。我试了一下用 button
来代替 Button
,删除了一个特定的事件监听器之后,文件上传功能可以执行了,不过我忘记是哪个特定的事件了,但是那个事件不是 button 本身的监听器而是其他的,会针对 button。
<input
accept={accept}
multiple={multiple}
onChange={fileChange}
type="file"
ref={inputRef}
style={{ display: 'none' }}
></input>
<Button handleClick={uploadClick} style={{ margin: '8px' }} type="primary">
<UploadOutlined />
上传
</Button>
-
第一种用
<label>
的方式是基于 HTML 标准的行为。标准的 HTML<label>
元素可以关联到其它字段,当用户点击<label>
时相当于点击了这些字段,甚至当这些字段不可见时也是这样。 -
第二种是更灵活的 JavaScript 方法。它不依赖于 HTML 的默认行为,而是需要额外的 JavaScript 代码来实现。通常在 uploadClick 函数内部会有一个额外的步骤来手动调用
<input>
元素的点击事件(比如 inputRef.current.click())。与第一种方法不同的是,这个<Button>
和<input>
之间的行为不是通过 HTML 结构来实现的,而是通过 JavaScript 来控制的。
记录一下过程:
-
添加字体文件到
src/assets/fonts
目录下 -
在
inedx.css
中引入(我这里没有使用 tailwind 的导入) -
定义
fontValue
的 state,和一个用于展示字体值的数组font_list
context 中传递fontValue
和setFontValue
还有handleChangeFont
用于切换字体的方法 -
RightBoard 中接收
handleChangeFont
,CenterBoard 中接收fontValue
- 定义了一个新的
ImageDownloadContext
, 并且在其中提供了一个imageContainerRef
和handleDownloadImage
- 在
RightBoard
中接收handleDownloadImage
,在CenterBoard
中接收imageContainerRef
react-konva
这个库中的 Line
组件要求传递的 strokeWidth,必须为
number 类型
我在 context 中定义了 penSize
,但是接收过来就成了 any
类型,查了一些文档之后,发现组件在传递数据的过程中,会因为多种原因导致数据类型丢失,所以这里就只能显示的定义一个数据类型了
interface ContextProp {
boardTool: string
penSize: number
}
const { boardTool, penSize } = useContext<ContextProp>(ImgContext)
// 监听键盘事件
const handleKeyDown = (e: KeyboardEvent) => {
// 判断一下电脑系统
const userAgent = navigator.userAgent.toLowerCase()
if (userAgent.indexOf('windows') > -1) {
// Windows系统
if (e.ctrlKey && e.key === 'z') {
// 移除最后一条线并更新状态
setLines(lines.slice(0, lines.length - 1))
}
} else if (userAgent.indexOf('mac') > -1) {
// Mac系统
if (e.metaKey && e.key === 'z') {
// 如果'command'键和'z'键同时被按下,移除最后一条线并更新状态
setLines(lines.slice(0, lines.length - 1))
}
}
}
当我将 if (e.metaKey && e.key === 'z')
改为 if (e.key === 'command' || e.key === 'z')
的时候,摁下 Command + Z
也会生效,我自己测试是这个键同时按下第二个代码才会生效,就很奇怪,这似乎违反了它的逻辑??
一开始我以为是路径问题,发现控制台的网络请求可以正确看到指针的图片,最后发现是图片大小的问题。 在 Chrome、Firefox 和 Safari 中,自定义光标图像的最大高度和宽度都为 32px。如果你的图像超过这个限制,那么它只会显示为默认的光标。
我用的是 hugging face 上的 stable-diffusion-xl-base-1.0
下面是 API 的使用
async function query(data) {
const response = await fetch(
'https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0',
{
headers: { Authorization: 'Bearer {API_TOKEN}' },
method: 'POST',
body: JSON.stringify(data),
}
)
const result = await response.blob()
return result
}
query({ inputs: 'Astronaut riding a horse' }).then((response) => {
// Use image
})
可以看到,API 返回的是一个 blob
对象,需要转换成 url 才能使用,因此我使用了 createObjectURL
来转换成 url, 但是这里有一个问题,就是这个数据是临时存在的,如果刷新页面,或者关闭,或者跳转页面,就会消失,因为我是只有一个页面,所以不存在这个问题;但我还是将其移动到了 Context
状态管理当中,这样就不会出现这个问题了。
主要是一个原因:每次加载就会请求 API,但是 unsplash 做了限制,每小时只能请求 50 次,所以这样去监听滚动事件,很快次数就会用光
疑问:是否有其他的解决方案。
我开始实现这个向下滚动实现加载更多图片的时候,考虑的是,我每次滑倒底部,监听滑动事件,触发一次请求 API,这样子就可以实现展示其他的图片。 这里有一个 bug,是 NextUI 的,因为我用了它的 ScrollShadow 组件,滚动的时候会有阴影效果,它这个会影响我写的监听滚动事件。