#!/usr/bin/env ruby # -*- coding: utf-8 -*- # 将PNG转换为systray可用的 []byte 格式 # 支持输出: Go byte slice 或 ICO 格式 require 'base64' require 'optparse' options = { size: 32, output_format: 'go', # 'go' | 'ico' | 'png' input: 'image.png', output: nil } OptionParser.new do |opts| opts.banner = "用法: ruby convert_icon.rb [选项]" opts.on("-s", "--size SIZE", Integer, "图标尺寸 (默认: 32)") { |s| options[:size] = s } opts.on("-f", "--format FORMAT", ["go", "ico", "png"], "输出格式: go/ico/png (默认: go)") { |f| options[:output_format] = f } opts.on("-i", "--input FILE", "输入PNG文件路径 (默认: image.png)") { |i| options[:input] = i } opts.on("-o", "--output FILE", "输出文件路径") { |o| options[:output] = o } opts.on("-h", "--help", "显示帮助") { puts opts; exit } end.parse! # 检查依赖 def check_mini_magick begin require 'mini_magick' true rescue LoadError false end end def check_chunky_png begin require 'chunky_png' true rescue LoadError false end end # 使用mini_magick (ImageMagick) 调整图片大小 def resize_with_magick(input_path, output_path, size) image = MiniMagick::Image.open(input_path) image.resize "#{size}x#{size}" image.write(output_path) output_path end # 使用chunky_png (纯Ruby) 调整图片大小 - 简单最近邻插值 def resize_with_chunky_png(input_path, output_path, size) require 'chunky_png' source = ChunkyPNG::Image.from_file(input_path) # 计算缩放比例 scale_x = source.width.to_f / size scale_y = source.height.to_f / size # 创建新图片 resized = ChunkyPNG::Image.new(size, size) size.times do |y| size.times do |x| src_x = (x * scale_x).to_i src_y = (y * scale_y).to_i src_x = [src_x, source.width - 1].min src_y = [src_y, source.height - 1].min resized[x, y] = source[src_x, src_y] end end resized.save(output_path) output_path end # 将图片转换为ICO格式 (多分辨率) def convert_to_ico(input_path, output_path, sizes = [16, 32, 48, 64]) require 'mini_magick' images = [] sizes.each do |size| img = MiniMagick::Image.open(input_path) img.resize "#{size}x#{size}" img.format 'png' temp_file = "temp_icon_#{size}.png" img.write(temp_file) images << temp_file end # 使用ImageMagick合并为ICO MiniMagick::Tool::Convert.new do |convert| images.each { |img| convert << img } convert << output_path end # 清理临时文件 images.each { |f| File.delete(f) if File.exist?(f) } output_path end # 生成Go []byte 格式 def generate_go_bytes(file_path, var_name = "iconData") bytes = File.binread(file_path).bytes lines = [] lines << "var #{var_name} = []byte{" bytes.each_slice(12) do |slice| hex_values = slice.map { |b| "0x%02X" % b } lines << " " + hex_values.join(", ") + "," end lines << "}" lines.join("\n") end # 生成 base64 内嵌格式 (另一种Go方案) def generate_go_base64(file_path, var_name = "iconData") data = File.binread(file_path) base64_str = Base64.strict_encode64(data) <<~GO var #{var_name}Base64 = `#{base64_str}` // 使用时解码: // import "encoding/base64" // iconData, _ := base64.StdEncoding.DecodeString(#{var_name}Base64) GO end # 主逻辑 puts "转换 systray 图标..." puts "输入文件: #{options[:input]}" puts "目标尺寸: #{options[:size]}x#{options[:size]}" unless File.exist?(options[:input]) puts "错误: 找不到输入文件 #{options[:input]}" exit 1 end # 选择处理方式 if check_mini_magick puts "使用 ImageMagick (mini_magick)..." elsif check_chunky_png puts "使用纯 Ruby (chunky_png)..." else puts "需要安装依赖. 请选择以下方式之一:" puts " 1. gem install mini_magick (推荐, 需要安装ImageMagick)" puts " 2. gem install chunky_png (纯Ruby, 无需ImageMagick)" exit 1 end begin if options[:output_format] == 'ico' # 生成ICO文件 output = options[:output] || "icon.ico" if check_mini_magick convert_to_ico(options[:input], output) else puts "生成ICO需要ImageMagick, 请先安装: gem install mini_magick" exit 1 end puts "已生成ICO文件: #{output}" elsif options[:output_format] == 'png' # 生成PNG文件 output = options[:output] || "icon_#{options[:size]}.png" if check_mini_magick resize_with_magick(options[:input], output, options[:size]) else resize_with_chunky_png(options[:input], output, options[:size]) end puts "已生成PNG文件: #{output}" else # go # 生成Go代码 temp_file = "temp_icon_#{options[:size]}.png" if check_mini_magick resize_with_magick(options[:input], temp_file, options[:size]) else resize_with_chunky_png(options[:input], temp_file, options[:size]) end go_code = generate_go_bytes(temp_file, "iconData") if options[:output] File.write(options[:output], go_code) puts "已生成Go代码文件: #{options[:output]}" else puts "\n=== 复制以下代码到你的Go文件 ===\n" puts go_code puts "\n=================================\n" end File.delete(temp_file) if File.exist?(temp_file) end puts "完成!" rescue => e puts "错误: #{e.message}" puts e.backtrace.first(5).join("\n") exit 1 end