// ImageWidth takes a file path (or sprite glob) and returns the // width in pixels of the image being referenced. func ImageWidth(mainctx context.Context, usv libsass.SassValue) (rsv *libsass.SassValue, err error) { var ( glob, name string ) comp, err := libsass.CompFromCtx(mainctx) if err != nil { return } err = libsass.Unmarshal(usv, &name) // Check for sprite-file override first if err != nil { var inf interface{} var infs []interface{} // Can't unmarshal to []interface{}, so unmarshal to // interface{} then reflect it into a []interface{} err = libsass.Unmarshal(usv, &inf) k := reflect.ValueOf(&infs).Elem() k.Set(reflect.ValueOf(inf)) if err != nil { return } glob = infs[0].(string) name = infs[1].(string) } paths := comp.(libsass.Pather) imgs := sw.New(&sw.Options{ ImageDir: paths.ImgDir(), BuildDir: paths.BuildDir(), GenImgDir: paths.ImgBuildDir(), }) loadctx := comp.Payload() var images payload.Payloader if len(glob) == 0 { images = payload.Image(loadctx) hit := images.Get(name) if hit != nil { imgs = hit } else { imgs.Decode(name) images.Set(name, imgs) } } else { // Glob present, look up in sprites sprites := payload.Sprite(loadctx) imgs = sprites.Get(glob) } w := imgs.SImageWidth(name) ww := libs.SassNumber{ Value: float64(w), Unit: "px", } res, err := libsass.Marshal(ww) return &res, err }
// Run is the main entrypoint for the cli. func run(paths []string, pMap *wt.SafePartialMap, gba *wt.BuildArgs) { // No paths given, read from stdin and wait if len(paths) == 0 { log.Println("Reading from stdin, -h for help") out := os.Stdout in := os.Stdin comp, err := wt.FromBuildArgs(out, nil, in, gba) if err != nil { log.Fatal(err) } err = comp.Run() if err != nil { color.Red(err.Error()) } return } bOpts := wt.NewBuild(paths, gba, pMap) err := bOpts.Run() if err != nil { log.Fatal(err) } // FIXME: move this to a Payload.Close() method // Before shutting down, check that every sprite has been // flushed to disk. img := sync.WaitGroup{} pMap.RLock() // It's not currently possible to wait on Image. This is often // to inline images, so it shouldn't be a factor... // for _, s := range gba.Payload.Image().M { // img.Add(1) // err := s.Wait() // img.Done() // if err != nil { // log.Printf("error writing image: %s\n", err) // } // } sprites := payload.Sprite(gba.Payload) sprites.ForEach(func(k string, sprite *spritewell.Sprite) { img.Add(1) err := sprite.Wait() img.Done() if err != nil { log.Printf("error writing sprite: %s\n", err) } }) img.Wait() pMap.RUnlock() }
// SpritePosition returns the position of the image in the sprite-map. // This is useful for passing directly to background-position func SpritePosition(mainctx context.Context, usv libsass.SassValue) (rsv *libsass.SassValue, err error) { comp, err := libsass.CompFromCtx(mainctx) if err != nil { return } var glob, name string err = libsass.Unmarshal(usv, &glob, &name) if err != nil { return } loadctx := comp.Payload() if loadctx == nil { err = ErrPayloadNil return } sprites := payload.Sprite(loadctx) if sprites == nil { err = errors.New("Sprites missing") return } imgs := sprites.Get(glob) if imgs == nil { err = fmt.Errorf( "Variable not found matching glob: %s sprite:%s", glob, name) return } if imgs.Lookup(name) == -1 { err = fmt.Errorf("image %s not found\n"+ " try one of these: %v", name, imgs.Paths()) return } // This is an odd name for what it does pos := imgs.GetPack(imgs.Lookup(name)) if err != nil { return } x := libs.SassNumber{Unit: "px", Value: float64(-pos.X)} y := libs.SassNumber{Unit: "px", Value: float64(-pos.Y)} str, err := libsass.Marshal( []libs.SassNumber{x, y}, ) return &str, err }
// Sprite returns the source and background position for an image in the // spritesheet. func Sprite(ctx context.Context, usv libsass.SassValue) (rsv *libsass.SassValue, err error) { comp, err := libsass.CompFromCtx(ctx) if err != nil { return nil, err } pather := comp.(libsass.Pather) var glob, name string var offsetX, offsetY libs.SassNumber err = libsass.Unmarshal(usv, &glob, &name, &offsetX, &offsetY) if err != nil { if err == libsass.ErrSassNumberNoUnit { err := fmt.Errorf( "Please specify unit for offset ie. (2px)") return nil, err } return nil, err } loadctx := comp.Payload() sprites := payload.Sprite(loadctx) imgs := sprites.Get(glob) if imgs == nil { err := fmt.Errorf( "Variable not found matching glob: %s sprite:%s", glob, name) return nil, err } path, err := imgs.OutputPath() if err != nil { return nil, err } buildDir := pather.BuildDir() genImgDir := pather.ImgBuildDir() httpPath := pather.HTTPPath() // FIXME: path directory can not be trusted, rebuild this from the context if len(httpPath) == 0 { ctxPath, err := filepath.Rel(buildDir, genImgDir) if err != nil { return nil, err } path = strings.Join([]string{ctxPath, filepath.Base(path)}, "/") } else { u, err := url.Parse(httpPath) if err != nil { return nil, err } u.Path = strings.Join([]string{u.Path, "build", filepath.Base(path)}, "/") path = u.String() } if err != nil { return nil, err } if imgs.Lookup(name) == -1 { return nil, fmt.Errorf("image %s not found\n"+ " try one of these: %v", name, imgs.Paths()) } // This is an odd name for what it does pos := imgs.GetPack(imgs.Lookup(name)) if err != nil { return nil, err } x := libs.SassNumber{Unit: "px", Value: float64(-pos.X)} x = x.Add(offsetX) y := libs.SassNumber{Unit: "px", Value: float64(-pos.Y)} y = y.Add(offsetY) str, err := libsass.Marshal( fmt.Sprintf(`url("%s") %s %s`, path, x, y, )) if err != nil { return nil, err } return &str, nil }
// SpriteMap returns a sprite from the passed glob and sprite // parameters. func SpriteMap(mainctx context.Context, usv libsass.SassValue) (*libsass.SassValue, error) { var glob string var spacing libs.SassNumber err := libsass.Unmarshal(usv, &glob, &spacing) if err != nil { return nil, err } comp, err := libsass.CompFromCtx(mainctx) if err != nil { return nil, err } paths := comp.(libsass.Pather) imgs := sw.New(&sw.Options{ ImageDir: paths.ImgDir(), BuildDir: paths.BuildDir(), GenImgDir: paths.ImgBuildDir(), Padding: int(spacing.Value), }) if cglob, err := strconv.Unquote(glob); err == nil { glob = cglob } key := glob + strconv.FormatInt(int64(spacing.Value), 10) loadctx := comp.Payload() sprites := payload.Sprite(loadctx) // FIXME: wtf is this? // sprites.RLock() // if _, ok := sprites.M[key]; ok { // defer sprites.RUnlock() // res, err := libsass.Marshal(key) // if err != nil { // return setErrorAndReturn(err, rsv) // } // if rsv != nil { // *rsv = res // } // return nil // } // sprites.RUnlock() err = imgs.Decode(glob) if err != nil { return nil, err } _, err = imgs.Export() if err != nil { return nil, err } res, err := libsass.Marshal(key) if err != nil { return nil, err } sprites.Set(key, imgs) return &res, nil }
// ImageHeight takes a file path (or sprite glob) and returns the // height in pixels of the image being referenced. func ImageHeight(mainctx context.Context, usv libsass.SassValue) (*libsass.SassValue, error) { var ( glob string name string ) comp, err := libsass.CompFromCtx(mainctx) if err != nil { return nil, err } err = libsass.Unmarshal(usv, &name) // Check for sprite-file override first if err != nil { var inf interface{} var infs []interface{} // Can't unmarshal to []interface{}, so unmarshal to // interface{} then reflect it into a []interface{} err = libsass.Unmarshal(usv, &inf) k := reflect.ValueOf(&infs).Elem() k.Set(reflect.ValueOf(inf)) if err != nil { return nil, err } glob = infs[0].(string) name = infs[1].(string) } paths := comp.(libsass.Pather) imgs := sw.New(&sw.Options{ ImageDir: paths.ImgDir(), BuildDir: paths.BuildDir(), GenImgDir: paths.ImgBuildDir(), }) loadctx := comp.Payload() if loadctx == nil { return nil, ErrPayloadNil } images := payload.Image(loadctx) if images == nil { return nil, errors.New("inline payload not available") } if len(glob) == 0 { exst := images.Get(name) if exst != nil { imgs = exst } else { imgs.Decode(name) // Store images in global cache images.Set(name, imgs) } } else { sprites := payload.Sprite(loadctx) imgs = sprites.Get(glob) if imgs == nil { return nil, errors.New("Sprite not found") } } height := imgs.SImageHeight(name) Hheight := libs.SassNumber{ Value: float64(height), Unit: "px", } res, err := libsass.Marshal(Hheight) return &res, err }