Skip to content

Instantly share code, notes, and snippets.

@unak
Created November 10, 2016 13:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save unak/3a44f1eed64389a918df8ea7fd3a29b3 to your computer and use it in GitHub Desktop.
Save unak/3a44f1eed64389a918df8ea7fd3a29b3 to your computer and use it in GitHub Desktop.
drawcmd.rb
if ARGV.size != 1
warn "Usage: ruby #$0 <image file>"
exit
end
image_file = ARGV.shift.encode("utf-16le")
require "fiddle/import"
module Kernel32
extend Fiddle::Importer
dlload "kernel32.dll"
extern "int GetLastError()"
extern "intptr_t GetConsoleWindow()"
extern "int GetConsoleScreenBufferInfo(intptr_t, void *)"
extern "int GetCurrentConsoleFont(intptr_t, int, void *)"
extern "intptr_t CreateFile(void *, unsigned int, unsigned int, void *, unsigned int, unsigned int, intptr_t)"
extern "int CloseHandle(intptr_t)"
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
OPEN_EXISTING = 3
CONSOLE_SCREEN_BUFFER_INFO = struct([
"short width",
"short height",
"short x",
"short y",
"unsigned short wAttribute",
"short left",
"short top",
"short right",
"short bottom",
"short maxWidth",
"short maxHeight",
])
CONSOLE_FONT_INFO = struct([
"unsigned int nFont",
"short width",
"short height",
])
end
module User32
extend Fiddle::Importer
dlload "user32.dll"
extern "intptr_t GetDC(intptr_t)"
extern "int ReleaseDC(intptr_t, intptr_t)"
extern "int GetClientRect(intptr_t, void *)"
RECT = struct([
"int left",
"int top",
"int right",
"int bottom",
])
end
module GdiPlus
extend Fiddle::Importer
dlload "gdiplus.dll"
extern "int GdiplusStartup(void *, void *, void *)"
extern "int GdiplusShutdown(void *)"
extern "int GdipCreateFromHWND(intptr_t, void *)"
extern "int GdipDeleteGraphics(void *)"
extern "int GdipLoadImageFromFile(void *, void *)"
extern "int GdipDrawImageI(void *, void *, int, int)"
extern "int GdipDrawImageRectI(void *, void *, int, int, int, int)"
extern "int GdipDisposeImage(void *)"
extern "int GdipGetImageWidth(void *, void *)"
extern "int GdipGetImageHeight(void *, void *)"
Pointer = struct([
"void *ptr"
])
UInt = struct([
"unsigned int value"
])
StartupInput = struct([
"unsigned int GdiPlusVersion",
"void *DebugEventCallback",
"int SuppressBackgroundThread",
"int SuppressExternalCodecs",
])
def self.method_missing(name, *args)
meth = ("Gdip" + name.to_s).to_sym
unless respond_to?(meth)
meth = ("Gdiplus" + name.to_s).to_sym
end
raise NoMethodError, "No such method: `#{name}'" unless respond_to?(meth)
status = __send__(meth, *args)
if status != 0
raise "GDI error: #{status}"
end
0
end
end
hcon = Kernel32.CreateFile("CONOUT$", Kernel32::GENERIC_READ | Kernel32::GENERIC_WRITE, 0, nil, Kernel32::OPEN_EXISTING, 0, 0)
raise "Cannot get console output handle" if hcon == -1
begin
fontinfo = Kernel32::CONSOLE_FONT_INFO.malloc
if Kernel32.GetCurrentConsoleFont(hcon, 0, fontinfo) == 0
raise "Cannot get console screen buffer info"
end
hwnd = Kernel32.GetConsoleWindow
raise "Cannot get console window handle" if hwnd == -1
tokenbuf = GdiPlus::Pointer.malloc
gsi = GdiPlus::StartupInput.malloc
gsi.GdiPlusVersion = 1
gsi.DebugEventCallback = nil
gsi.SuppressBackgroundThread = 0
gsi.SuppressExternalCodecs = 0
GdiPlus.Startup(tokenbuf, gsi, nil)
begin
grbuf = GdiPlus::Pointer.malloc
GdiPlus.CreateFromHWND(hwnd, grbuf)
begin
imagebuf = GdiPlus::Pointer.malloc
GdiPlus.LoadImageFromFile(image_file, imagebuf)
begin
buf = GdiPlus::UInt.malloc
GdiPlus.GetImageWidth(imagebuf.ptr, buf)
w = buf.value
GdiPlus.GetImageHeight(imagebuf.ptr, buf)
h = buf.value
rect = User32::RECT.malloc
if User32.GetClientRect(hwnd, rect) == 0
raise "cannot call GetClientRect"
end
cw = rect.right - rect.left
ch = rect.bottom - rect.top - fontinfo.height
if w > cw
h = cw*h/w
w = cw
end
if h > ch
w = w*ch/h
h = ch
end
n = h / fontinfo.height
n.times do
puts
end
coninfo = Kernel32::CONSOLE_SCREEN_BUFFER_INFO.malloc
if Kernel32.GetConsoleScreenBufferInfo(hcon, coninfo) == 0
raise "Cannot get console screen buffer info"
end
y = ((coninfo.y - n) - coninfo.top) * fontinfo.height
GdiPlus.DrawImageRectI(grbuf.ptr, imagebuf.ptr, 0, y, w, h)
ensure
GdiPlus.DisposeImage(imagebuf.ptr)
end
ensure
GdiPlus.DeleteGraphics(grbuf.ptr)
end
ensure
GdiPlus.Shutdown(tokenbuf.ptr)
end
ensure
Kernel32.CloseHandle(hcon)
end
@unak
Copy link
Author

unak commented Nov 10, 2016

https://github.com/mattn/drawcmd のドキュメントだけ読んで「なるほど」と思って雑に書いてみたもの。
コードは読まなかったので、同じことをやってるのか、とか、同じ機能を満たしてるのか、とかは未確認。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment