| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756 |
- // Copyright 2018 visualfc. All rights reserved.
- //go:build !windows
- // +build !windows
- package interp
- import (
- "errors"
- "fmt"
- "image"
- "image/color"
- "image/draw"
- "os"
- "unsafe"
- )
- /*
- #cgo darwin CFLAGS: -I/Library/Frameworks/Tcl.framework/Headers -I/Library/Frameworks/Tk.framework/Headers
- #cgo darwin LDFLAGS: -F/Library/Frameworks -framework tcl -framework tk
- #cgo linux CFLAGS: -I/usr/include/tcl
- #cgo linux LDFLAGS: -ltcl -ltk -lX11 -lm -lz -ldl
- #include <tcl.h>
- #include <tk.h>
- #include <stdlib.h>
- extern int _go_async_event_handler(Tcl_Event*, int);
- static Tcl_Event* _c_create_async_event()
- {
- Tcl_Event *ev = (Tcl_Event*)Tcl_Alloc(sizeof(Tcl_Event));
- ev->proc = &_go_async_event_handler;
- ev->nextPtr = 0;
- return ev;
- }
- static void _c_send_async_event(Tcl_ThreadId tid, Tcl_Event *ev)
- {
- Tcl_ThreadQueueEvent(tid, ev, TCL_QUEUE_TAIL);
- Tcl_ThreadAlert(tid);
- }
- extern int _go_tcl_objcmd_proc(void *clientData, Tcl_Interp *interp, int objc, void *objv);
- extern void _go_tcl_deletecmd_proc(void *clientData);
- static int _c_tcl_objcmd_proc(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
- {
- return _go_tcl_objcmd_proc(clientData, interp, objc, (Tcl_Obj**)objv);
- }
- static Tcl_Command _c_create_obj_command(Tcl_Interp *interp, char *name, void* clientData)
- {
- return Tcl_CreateObjCommand(interp,name,_c_tcl_objcmd_proc,clientData,&_go_tcl_deletecmd_proc);
- }
- extern int _go_tcl_actioncmd_proc(void *clientData, Tcl_Interp *interp, int objc, void *objv);
- extern void _go_tcl_deleteaction_proc(void *clientData);
- static int _c_tcl_actioncmd_proc(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
- {
- return _go_tcl_actioncmd_proc(clientData, interp, objc, (Tcl_Obj**)objv);
- }
- static Tcl_Command _c_create_action_command(Tcl_Interp *interp, char *name, void* clientData)
- {
- return Tcl_CreateObjCommand(interp,name,_c_tcl_actioncmd_proc,clientData,&_go_tcl_deleteaction_proc);
- }
- static void _c_wrong_num_args(Tcl_Interp *interp, int objc, void *objv, char *message)
- {
- Tcl_WrongNumArgs(interp, objc, (Tcl_Obj**)objv, message) ;
- }
- */
- import "C"
- var (
- mainLoopThreadId C.Tcl_ThreadId
- )
- //export _go_tcl_objcmd_proc
- func _go_tcl_objcmd_proc(clientData unsafe.Pointer, interp *C.Tcl_Interp, objc C.int, objv unsafe.Pointer) C.int {
- objs := (*(*[1 << 20]*C.Tcl_Obj)(objv))[1:objc:objc]
- var args []string
- for _, obj := range objs {
- args = append(args, objToString(interp, obj))
- }
- result, err := globalCommandMap.Invoke(uintptr(clientData), args)
- if err != nil {
- cs := C.CString(err.Error())
- defer C.free(unsafe.Pointer(cs))
- C._c_wrong_num_args(interp, 1, objv, cs)
- return TCL_ERROR
- }
- if result != "" {
- C.Tcl_SetObjResult(interp, stringToObj(result))
- }
- return TCL_OK
- }
- //export _go_tcl_deletecmd_proc
- func _go_tcl_deletecmd_proc(clientData unsafe.Pointer) {
- globalCommandMap.UnRegister(uintptr(clientData))
- return
- }
- //export _go_tcl_actioncmd_proc
- func _go_tcl_actioncmd_proc(clientData unsafe.Pointer, interp *C.Tcl_Interp, objc C.int, objv unsafe.Pointer) C.int {
- objs := (*(*[1 << 20]*C.Tcl_Obj)(objv))[1:objc:objc]
- var args []string
- for _, obj := range objs {
- args = append(args, objToString(interp, obj))
- }
- err := globalActionMap.Invoke(uintptr(clientData), args)
- if err != nil {
- cs := C.CString(err.Error())
- defer C.free(unsafe.Pointer(cs))
- C._c_wrong_num_args(interp, 1, objv, cs)
- return TCL_ERROR
- }
- return TCL_OK
- }
- //export _go_tcl_deleteaction_proc
- func _go_tcl_deleteaction_proc(clientData unsafe.Pointer) {
- globalActionMap.UnRegister(uintptr(clientData))
- return
- }
- //export _go_async_event_handler
- func _go_async_event_handler(ev *C.Tcl_Event, flags C.int) C.int {
- if flags != C.TK_ALL_EVENTS {
- return 0
- }
- if fn, ok := globalAsyncEvent.Load(unsafe.Pointer(ev)); ok {
- fn.(func())()
- globalAsyncEvent.Delete(unsafe.Pointer(ev))
- }
- return 1
- }
- func IsMainThread() bool {
- return C.Tcl_GetCurrentThread() == mainLoopThreadId
- }
- func async_send_event(tid C.Tcl_ThreadId, fn func()) {
- ev := C._c_create_async_event()
- globalAsyncEvent.Store(unsafe.Pointer(ev), fn)
- C._c_send_async_event(tid, ev)
- }
- func Async(fn func()) {
- if fn == nil {
- return
- }
- async_send_event(mainLoopThreadId, fn)
- }
- func MainLoop(fn func()) {
- mainLoopThreadId = C.Tcl_GetCurrentThread()
- if fn != nil {
- fn()
- }
- C.Tk_MainLoop()
- mainLoopThreadId = nil
- }
- type Interp struct {
- interp *C.Tcl_Interp
- supportTk86 bool
- }
- func NewInterp() (*Interp, error) {
- interp := C.Tcl_CreateInterp()
- if interp == nil {
- return nil, errors.New("Tcl_CreateInterp failed")
- }
- return &Interp{interp, false}, nil
- }
- func (p *Interp) SupportTk86() bool {
- return p.supportTk86
- }
- func (p *Interp) InitTcl(tcl_library string) error {
- if tcl_library != "" {
- p.Eval(fmt.Sprintf("set tcl_library {%s}", tcl_library))
- }
- if C.Tcl_Init(p.interp) != TCL_OK {
- err := errors.New("Tcl_Init failed")
- return err
- }
- return nil
- }
- func (p *Interp) InitTk(tk_library string) error {
- if tk_library != "" {
- p.Eval(fmt.Sprintf("set tk_library {%s}", tk_library))
- }
- if C.Tk_Init(p.interp) != TCL_OK {
- err := errors.New("Tk_Init failed")
- return err
- }
- p.supportTk86 = p.TkVersion() >= "8.6"
- return nil
- }
- func (p *Interp) Destroy() error {
- if p == nil || p.interp == nil {
- return os.ErrInvalid
- }
- C.Tcl_DeleteInterp(p.interp)
- p.interp = nil
- return nil
- }
- func (p *Interp) GetObjResult() *Obj {
- return &Obj{C.Tcl_GetObjResult(p.interp), p.interp}
- }
- func (p *Interp) GetListObjResult() *ListObj {
- return &ListObj{C.Tcl_GetObjResult(p.interp), p.interp}
- }
- func (p *Interp) Eval(script string) error {
- cs := C.CString(script)
- defer C.free(unsafe.Pointer(cs))
- if C.Tcl_EvalEx(p.interp, cs, C.int(len(script)), 0) != TCL_OK {
- err := errors.New(p.GetStringResult())
- return err
- }
- return nil
- }
- func (p *Interp) CreateCommand(name string, fn func([]string) (string, error)) (uintptr, error) {
- cs := C.CString(name)
- defer C.free(unsafe.Pointer(cs))
- id := globalCommandMap.Register(fn)
- cmd := C._c_create_obj_command(p.interp, cs, unsafe.Pointer(id))
- if cmd == nil {
- err := fmt.Errorf("CreateCommand %v failed", name)
- return 0, err
- }
- return id, nil
- }
- func (p *Interp) InvokeCommand(id uintptr, args []string) (string, error) {
- return globalCommandMap.Invoke(id, args)
- }
- func (p *Interp) CreateAction(name string, fn func([]string)) (uintptr, error) {
- cs := C.CString(name)
- defer C.free(unsafe.Pointer(cs))
- id := globalActionMap.Register(fn)
- cmd := C._c_create_action_command(p.interp, cs, unsafe.Pointer(id))
- if cmd == nil {
- err := fmt.Errorf("CreateAction %v failed", name)
- return 0, err
- }
- return id, nil
- }
- func (p *Interp) InvokeAction(id uintptr, args []string) error {
- return globalActionMap.Invoke(id, args)
- }
- func (p *Interp) GetVar(name string, global bool) *Obj {
- cname := C.CString(name)
- defer C.free(unsafe.Pointer(cname))
- var flag C.int = C.TCL_LEAVE_ERR_MSG
- if global {
- flag |= C.TCL_GLOBAL_ONLY
- }
- obj := C.Tcl_GetVar2Ex(p.interp, cname, nil, flag)
- if obj == nil {
- return nil
- }
- return &Obj{obj, p.interp}
- }
- func (p *Interp) GetList(name string, global bool) *ListObj {
- return (*ListObj)(p.GetVar(name, global))
- }
- func (p *Interp) SetStringList(name string, list []string, global bool) error {
- obj := NewListObj(p)
- obj.AppendStringList(list)
- return p.SetVarObj(name, (*Obj)(obj), global)
- }
- func (p *Interp) AppendStringListList(name string, list []string, global bool) error {
- cname := C.CString(name)
- defer C.free(unsafe.Pointer(cname))
- var flag C.int = C.TCL_LEAVE_ERR_MSG | C.TCL_APPEND_VALUE | C.TCL_LIST_ELEMENT
- if global {
- flag |= C.TCL_GLOBAL_ONLY
- }
- for _, value := range list {
- cvalue := C.CString(value)
- C.Tcl_SetVar(p.interp, cname, cvalue, flag)
- C.free(unsafe.Pointer(cvalue))
- }
- return nil
- }
- func (p *Interp) AppendStringList(name string, value string, global bool) error {
- cname := C.CString(name)
- defer C.free(unsafe.Pointer(cname))
- cvalue := C.CString(value)
- defer C.free(unsafe.Pointer(cvalue))
- var flag C.int = C.TCL_LEAVE_ERR_MSG | C.TCL_APPEND_VALUE | C.TCL_LIST_ELEMENT
- if global {
- flag |= C.TCL_GLOBAL_ONLY
- }
- r := C.Tcl_SetVar(p.interp, cname, cvalue, flag)
- if r == nil {
- return p.GetErrorResult()
- }
- return nil
- }
- func (p *Interp) SetVarObj(name string, obj *Obj, global bool) error {
- if obj == nil {
- return os.ErrInvalid
- }
- cname := C.CString(name)
- defer C.free(unsafe.Pointer(cname))
- var flag C.int = C.TCL_LEAVE_ERR_MSG
- if global {
- flag |= C.TCL_GLOBAL_ONLY
- }
- r := C.Tcl_SetVar2Ex(p.interp, cname, nil, obj.obj, flag)
- if r == nil {
- return p.GetErrorResult()
- }
- return nil
- }
- func (p *Interp) SetVarListObj(name string, obj *ListObj, global bool) error {
- return p.SetVarObj(name, (*Obj)(obj), global)
- }
- func (p *Interp) SetStringVar(name string, value string, global bool) error {
- cname := C.CString(name)
- defer C.free(unsafe.Pointer(cname))
- cvalue := C.CString(value)
- defer C.free(unsafe.Pointer(cvalue))
- var flag C.int = C.TCL_LEAVE_ERR_MSG
- if global {
- flag |= C.TCL_GLOBAL_ONLY
- }
- r := C.Tcl_SetVar(p.interp, cname, cvalue, flag)
- if r == nil {
- return p.GetErrorResult()
- }
- return nil
- }
- func (p *Interp) AppendStringVar(name string, value string, global bool) error {
- cname := C.CString(name)
- defer C.free(unsafe.Pointer(cname))
- cvalue := C.CString(value)
- defer C.free(unsafe.Pointer(cvalue))
- var flag C.int = C.TCL_LEAVE_ERR_MSG | C.TCL_APPEND_VALUE
- if global {
- flag |= C.TCL_GLOBAL_ONLY
- }
- r := C.Tcl_SetVar(p.interp, cname, cvalue, flag)
- if r == nil {
- return p.GetErrorResult()
- }
- return nil
- }
- func (p *Interp) UnsetVar(name string, global bool) error {
- cname := C.CString(name)
- defer C.free(unsafe.Pointer(cname))
- var flag C.int = C.TCL_LEAVE_ERR_MSG
- if global {
- flag |= C.TCL_GLOBAL_ONLY
- }
- r := C.Tcl_UnsetVar(p.interp, cname, flag)
- if r != C.TCL_OK {
- return p.GetErrorResult()
- }
- return nil
- }
- type Obj struct {
- obj *C.Tcl_Obj
- interp *C.Tcl_Interp
- }
- func (o *Obj) ToFloat64() float64 {
- var out C.double
- status := C.Tcl_GetDoubleFromObj(o.interp, o.obj, &out)
- if status == C.TCL_OK {
- return float64(out)
- }
- return 0
- }
- func (o *Obj) ToInt64() int64 {
- var out C.Tcl_WideInt
- status := C.Tcl_GetWideIntFromObj(o.interp, o.obj, &out)
- if status == TCL_OK {
- return int64(out)
- }
- return 0
- }
- func (o *Obj) ToInt() int {
- return int(o.ToInt64())
- }
- func (o *Obj) ToUint() uint {
- return uint(o.ToInt64())
- }
- func (o *Obj) ToBool() bool {
- var out C.int
- status := C.Tcl_GetBooleanFromObj(o.interp, o.obj, &out)
- if status == C.TCL_OK {
- return out == 1
- }
- return false
- }
- func (o *Obj) ToString() string {
- var n C.int
- out := C.Tcl_GetStringFromObj(o.obj, &n)
- return C.GoStringN(out, n)
- }
- func NewStringObj(value string, p *Interp) *Obj {
- cs := C.CString(value)
- defer C.free(unsafe.Pointer(cs))
- return &Obj{C.Tcl_NewStringObj(cs, C.int(len(value))), p.interp}
- }
- func NewFloat64Obj(value float64, p *Interp) *Obj {
- return &Obj{C.Tcl_NewDoubleObj(C.double(value)), p.interp}
- }
- func NewInt64Obj(value int64, p *Interp) *Obj {
- return &Obj{C.Tcl_NewWideIntObj(C.Tcl_WideInt(value)), p.interp}
- }
- func NewIntObj(value int, p *Interp) *Obj {
- return &Obj{C.Tcl_NewWideIntObj(C.Tcl_WideInt(value)), p.interp}
- }
- func NewBoolObj(value bool, p *Interp) *Obj {
- if value {
- return &Obj{C.Tcl_NewBooleanObj(1), p.interp}
- } else {
- return &Obj{C.Tcl_NewBooleanObj(0), p.interp}
- }
- }
- func objToString(interp *C.Tcl_Interp, obj *C.Tcl_Obj) string {
- var n C.int
- out := C.Tcl_GetStringFromObj(obj, &n)
- return C.GoStringN(out, n)
- }
- func stringToObj(value string) *C.Tcl_Obj {
- cs := C.CString(value)
- defer C.free(unsafe.Pointer(cs))
- return C.Tcl_NewStringObj(cs, C.int(len(value)))
- }
- type ListObj Obj
- func NewListObj(p *Interp) *ListObj {
- o := C.Tcl_NewListObj(0, nil)
- return &ListObj{o, p.interp}
- }
- func (o *ListObj) Length() int {
- var length C.int
- C.Tcl_ListObjLength(o.interp, o.obj, &length)
- return int(length)
- }
- func (o *ListObj) IndexObj(index int) *Obj {
- var obj *C.Tcl_Obj
- r := C.Tcl_ListObjIndex(o.interp, o.obj, C.int(index), &obj)
- if r != C.TCL_OK || obj == nil {
- return nil
- }
- return &Obj{obj, o.interp}
- }
- func (o *ListObj) IndexString(index int) string {
- var obj *C.Tcl_Obj
- r := C.Tcl_ListObjIndex(o.interp, o.obj, C.int(index), &obj)
- if r != C.TCL_OK || obj == nil {
- return ""
- }
- return objToString(o.interp, obj)
- }
- func (o *ListObj) ToObjList() (list []*Obj) {
- var objs **C.Tcl_Obj
- var objnum C.int
- C.Tcl_ListObjGetElements(o.interp, o.obj, &objnum, &objs)
- if objnum == 0 {
- return
- }
- lst := (*[1 << 28]*C.Tcl_Obj)(unsafe.Pointer(objs))[:int(objnum):int(objnum)]
- for _, v := range lst {
- list = append(list, &Obj{v, o.interp})
- }
- return
- }
- func (o *ListObj) ToStringList() (list []string) {
- var objs **C.Tcl_Obj
- var objnum C.int
- C.Tcl_ListObjGetElements(o.interp, o.obj, &objnum, &objs)
- if objnum == 0 {
- return
- }
- lst := (*[1 << 28]*C.Tcl_Obj)(unsafe.Pointer(objs))[:int(objnum):int(objnum)]
- var n C.int
- for _, obj := range lst {
- out := C.Tcl_GetStringFromObj(obj, &n)
- list = append(list, C.GoStringN(out, n))
- }
- return
- }
- func (o *ListObj) ToIntList() (list []int) {
- var objs **C.Tcl_Obj
- var objnum C.int
- C.Tcl_ListObjGetElements(o.interp, o.obj, &objnum, &objs)
- if objnum == 0 {
- return
- }
- lst := (*[1 << 28]*C.Tcl_Obj)(unsafe.Pointer(objs))[:int(objnum):int(objnum)]
- var out C.Tcl_WideInt
- for _, obj := range lst {
- C.Tcl_GetWideIntFromObj(o.interp, obj, &out)
- list = append(list, int(out))
- }
- return
- }
- func (o *ListObj) SetStringList(list []string) {
- C.Tcl_SetListObj(o.obj, 0, nil)
- o.AppendStringList(list)
- }
- func (o *ListObj) AppendStringList(list []string) {
- for _, v := range list {
- cs := C.CString(v)
- obj := C.Tcl_NewStringObj(cs, C.int(len(v)))
- C.Tcl_ListObjAppendElement(o.interp, o.obj, obj)
- C.free(unsafe.Pointer(cs))
- }
- }
- func (o *ListObj) AppendObj(obj *Obj) bool {
- if obj == nil {
- return false
- }
- C.Tcl_ListObjAppendElement(o.interp, o.obj, obj.obj)
- return true
- }
- func (o *ListObj) AppendString(s string) {
- C.Tcl_ListObjAppendElement(o.interp, o.obj, stringToObj(s))
- }
- func (o *ListObj) InsertObj(index int, obj *Obj) {
- C.Tcl_ListObjReplace(o.interp, o.obj, C.int(index), 0, 1, &obj.obj)
- }
- func (o *ListObj) InsertString(index int, s string) {
- obj := stringToObj(s)
- C.Tcl_ListObjReplace(o.interp, o.obj, C.int(index), 0, 1, &obj)
- }
- func (o *ListObj) SetIndexObj(index int, obj *Obj) bool {
- if obj == nil {
- return false
- }
- C.Tcl_ListObjReplace(o.interp, o.obj, C.int(index), 1, 1, &obj.obj)
- return true
- }
- func (o *ListObj) SetIndexString(index int, s string) {
- obj := stringToObj(s)
- C.Tcl_ListObjReplace(o.interp, o.obj, C.int(index), 1, 1, &obj)
- }
- func (o *ListObj) Remove(first int, count int) {
- C.Tcl_ListObjReplace(o.interp, o.obj, C.int(first), C.int(count), 0, nil)
- }
- type Photo struct {
- handle C.Tk_PhotoHandle
- interp *Interp
- }
- func FindPhoto(interp *Interp, imageName string) *Photo {
- cs := C.CString(imageName)
- defer C.free(unsafe.Pointer(cs))
- handle := C.Tk_FindPhoto(interp.interp, cs)
- if handle == nil {
- return nil
- }
- return &Photo{handle, interp}
- }
- func (p *Photo) Blank() {
- C.Tk_PhotoBlank(p.handle)
- }
- func (p *Photo) SetSize(width int, height int) error {
- status := C.Tk_PhotoSetSize(p.interp.interp, p.handle, C.int(width), C.int(height))
- if status != C.TCL_OK {
- return p.interp.GetErrorResult()
- }
- return nil
- }
- func (p *Photo) Size() (int, int) {
- var width, height C.int
- C.Tk_PhotoGetSize(p.handle, &width, &height)
- return int(width), int(height)
- }
- func (p *Photo) Expand(width int, height int) error {
- status := C.Tk_PhotoExpand(p.interp.interp, p.handle, C.int(width), C.int(height))
- if status != C.TCL_OK {
- return p.interp.GetErrorResult()
- }
- return nil
- }
- func (p *Photo) ToImage() image.Image {
- var block C.Tk_PhotoImageBlock
- C.Tk_PhotoGetImage(p.handle, &block)
- if block.width == 0 || block.height == 0 {
- return nil
- }
- r := image.Rect(0, 0, int(block.width), int(block.height))
- pix := C.GoBytes(unsafe.Pointer(block.pixelPtr), C.int(4*block.width*block.height))
- return &image.NRGBA{pix, 4 * int(block.width), r}
- }
- func (p *Photo) PutImage(img image.Image, tk85alphacolor color.Color) error {
- if img == nil || img.Bounds().Empty() {
- return os.ErrInvalid
- }
- var pixelPtr unsafe.Pointer
- var stride int
- if p.interp.supportTk86 {
- dstImage, ok := img.(*image.NRGBA)
- if !ok {
- dstImage = image.NewNRGBA(img.Bounds())
- draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Src)
- }
- stride = dstImage.Stride
- pixelPtr = toCBytes(dstImage.Pix)
- } else {
- var r, g, b uint8
- if tk85alphacolor != nil {
- clr := color.RGBAModel.Convert(tk85alphacolor).(color.RGBA)
- r, g, b = clr.R, clr.G, clr.B
- }
- dstImage := image.NewRGBA(img.Bounds())
- for i := 0; i < len(dstImage.Pix); i += 4 {
- dstImage.Pix[i+0] = r
- dstImage.Pix[i+1] = g
- dstImage.Pix[i+2] = b
- dstImage.Pix[i+3] = 0xff
- }
- draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Over)
- stride = dstImage.Stride
- pixelPtr = toCBytes(dstImage.Pix)
- }
- defer C.free(pixelPtr)
- width := img.Bounds().Dx()
- height := img.Bounds().Dy()
- offset := [4]C.int{0, 1, 2, 3}
- block := C.Tk_PhotoImageBlock{
- (*C.uchar)(pixelPtr),
- C.int(width),
- C.int(height),
- C.int(stride),
- 4,
- offset,
- }
- status := C.Tk_PhotoPutBlock(p.interp.interp, p.handle, &block,
- 0, 0, C.int(width), C.int(height),
- C.TK_PHOTO_COMPOSITE_SET)
- if status != C.TCL_OK {
- return p.interp.GetErrorResult()
- }
- return nil
- }
- func (p *Photo) PutZoomedImage(img image.Image, zoomX, zoomY, subsampleX, subsampleY int, tk85alphacolor color.Color) error {
- if img == nil || img.Bounds().Empty() {
- return os.ErrInvalid
- }
- var pixelPtr unsafe.Pointer
- var stride int
- if p.interp.supportTk86 {
- dstImage, ok := img.(*image.NRGBA)
- if !ok {
- dstImage = image.NewNRGBA(img.Bounds())
- draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Src)
- }
- stride = dstImage.Stride
- pixelPtr = toCBytes(dstImage.Pix)
- } else {
- var r, g, b uint8
- if tk85alphacolor != nil {
- clr := color.RGBAModel.Convert(tk85alphacolor).(color.RGBA)
- r, g, b = clr.R, clr.G, clr.B
- }
- dstImage := image.NewRGBA(img.Bounds())
- for i := 0; i < len(dstImage.Pix); i += 4 {
- dstImage.Pix[i+0] = r
- dstImage.Pix[i+1] = g
- dstImage.Pix[i+2] = b
- dstImage.Pix[i+3] = 0xff
- }
- draw.Draw(dstImage, dstImage.Bounds(), img, img.Bounds().Min, draw.Over)
- stride = dstImage.Stride
- pixelPtr = toCBytes(dstImage.Pix)
- }
- defer C.free(pixelPtr)
- width := img.Bounds().Dx()
- height := img.Bounds().Dy()
- offset := [4]C.int{0, 1, 2, 3}
- block := C.Tk_PhotoImageBlock{
- (*C.uchar)(pixelPtr),
- C.int(width),
- C.int(height),
- C.int(stride),
- 4,
- offset,
- }
- status := C.Tk_PhotoPutZoomedBlock(p.interp.interp, p.handle, &block,
- 0, 0, C.int(width), C.int(height),
- C.int(zoomX), C.int(zoomY), C.int(subsampleX), C.int(subsampleY),
- C.TK_PHOTO_COMPOSITE_SET)
- if status != C.TCL_OK {
- return p.interp.GetErrorResult()
- }
- return nil
- }
|