Use buffer for ClassIcon EditableImages (#1149)

This commit is contained in:
quaywinn
2025-11-07 16:07:19 -05:00
committed by GitHub
parent 825726c883
commit 03410ced6d
2 changed files with 55 additions and 20 deletions

View File

@@ -1,6 +1,11 @@
local StudioService = game:GetService("StudioService") local StudioService = game:GetService("StudioService")
local AssetService = game:GetService("AssetService") local AssetService = game:GetService("AssetService")
type CachedImageInfo = {
pixels: buffer,
size: Vector2,
}
local Rojo = script:FindFirstAncestor("Rojo") local Rojo = script:FindFirstAncestor("Rojo")
local Plugin = Rojo.Plugin local Plugin = Rojo.Plugin
local Packages = Rojo.Packages local Packages = Rojo.Packages
@@ -11,44 +16,71 @@ local e = Roact.createElement
local EditableImage = require(Plugin.App.Components.EditableImage) local EditableImage = require(Plugin.App.Components.EditableImage)
local imageCache = {} local imageCache: { [string]: CachedImageInfo } = {}
local function getImageSizeAndPixels(image)
if not imageCache[image] then local function cloneBuffer(b: buffer): buffer
local editableImage = AssetService:CreateEditableImageAsync(image) local newBuffer = buffer.create(buffer.len(b))
buffer.copy(newBuffer, 0, b)
return newBuffer
end
local function getImageSizeAndPixels(image: string): (Vector2, buffer)
local cachedImage = imageCache[image]
if not cachedImage then
local editableImage = AssetService:CreateEditableImageAsync(Content.fromUri(image))
local size = editableImage.Size
local pixels = editableImage:ReadPixelsBuffer(Vector2.zero, size)
imageCache[image] = { imageCache[image] = {
Size = editableImage.Size, pixels = pixels,
Pixels = editableImage:ReadPixels(Vector2.zero, editableImage.Size), size = size,
} }
return size, cloneBuffer(pixels)
end end
return imageCache[image].Size, table.clone(imageCache[image].Pixels) return cachedImage.size, cloneBuffer(cachedImage.pixels)
end end
local function getRecoloredClassIcon(className, color) local function getRecoloredClassIcon(className, color)
local iconProps = StudioService:GetClassIcon(className) local iconProps = StudioService:GetClassIcon(className)
if iconProps and color then if iconProps and color then
local success, editableImageSize, editableImagePixels = pcall(function() --stylua: ignore
local size, pixels = getImageSizeAndPixels(iconProps.Image) local success, editableImageSize, editableImagePixels = pcall(function(_iconProps: { [any]: any }, _color: Color3): (Vector2, buffer)
local size, pixels = getImageSizeAndPixels(_iconProps.Image)
local pixelsLen = buffer.len(pixels)
local minVal, maxVal = math.huge, -math.huge local minVal, maxVal = math.huge, -math.huge
for i = 1, #pixels, 4 do
if pixels[i + 3] == 0 then for i = 0, pixelsLen, 4 do
if buffer.readu8(pixels, i + 3) == 0 then
continue continue
end end
local pixelVal = math.max(pixels[i], pixels[i + 1], pixels[i + 2]) local pixelVal = math.max(
buffer.readu8(pixels, i),
buffer.readu8(pixels, i + 1),
buffer.readu8(pixels, i + 2)
)
minVal = math.min(minVal, pixelVal) minVal = math.min(minVal, pixelVal)
maxVal = math.max(maxVal, pixelVal) maxVal = math.max(maxVal, pixelVal)
end end
local hue, sat, val = color:ToHSV() local hue, sat, val = _color:ToHSV()
for i = 1, #pixels, 4 do
if pixels[i + 3] == 0 then for i = 0, pixelsLen, 4 do
if buffer.readu8(pixels, i + 3) == 0 then
continue continue
end end
local gIndex = i + 1
local bIndex = i + 2
local pixelVal = math.max(pixels[i], pixels[i + 1], pixels[i + 2]) local pixelVal = math.max(
buffer.readu8(pixels, i),
buffer.readu8(pixels, gIndex),
buffer.readu8(pixels, bIndex)
)
local newVal = val local newVal = val
if minVal < maxVal then if minVal < maxVal then
-- Remap minVal - maxVal to val*0.9 - val -- Remap minVal - maxVal to val*0.9 - val
@@ -56,10 +88,12 @@ local function getRecoloredClassIcon(className, color)
end end
local newPixelColor = Color3.fromHSV(hue, sat, newVal) local newPixelColor = Color3.fromHSV(hue, sat, newVal)
pixels[i], pixels[i + 1], pixels[i + 2] = newPixelColor.R, newPixelColor.G, newPixelColor.B buffer.writeu8(pixels, i, newPixelColor.R)
buffer.writeu8(pixels, gIndex, newPixelColor.G)
buffer.writeu8(pixels, bIndex, newPixelColor.B)
end end
return size, pixels return size, pixels
end) end, iconProps, color)
if success then if success then
iconProps.EditableImagePixels = editableImagePixels iconProps.EditableImagePixels = editableImagePixels
iconProps.EditableImageSize = editableImageSize iconProps.EditableImageSize = editableImageSize

View File

@@ -12,7 +12,8 @@ function EditableImage:init()
end end
function EditableImage:writePixels() function EditableImage:writePixels()
local image = self.ref.current local image = self.ref.current :: EditableImage
if not image then if not image then
return return
end end
@@ -20,7 +21,7 @@ function EditableImage:writePixels()
return return
end end
image:WritePixels(Vector2.zero, self.props.size, self.props.pixels) image:WritePixelsBuffer(Vector2.zero, self.props.size, self.props.pixels)
end end
function EditableImage:render() function EditableImage:render()