// 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 }
// 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 }
// FontURL builds a relative path to the requested font file from the built CSS. func FontURL(ctx context.Context, usv libsass.SassValue) (*libsass.SassValue, error) { var ( path, format string csv libsass.SassValue raw bool ) comp, err := libsass.CompFromCtx(ctx) if err != nil { return nil, err } err = libsass.Unmarshal(usv, &path, &raw) if err != nil { return nil, err } paths := comp.(libsass.Pather) fdir := paths.FontDir() // Enter warning if fdir == "." || fdir == "" { s := "font-url: font path not set" return nil, errors.New(s) } rel, err := filepath.Rel(paths.BuildDir(), fdir) if err != nil { return nil, err } if raw { format = "%s%s" } else { format = `url("%s%s")` } abspath := filepath.Join(fdir, path) qry, err := qs(comp.CacheBust(), abspath) if err != nil { return nil, err } csv, err = libsass.Marshal(fmt.Sprintf(format, filepath.ToSlash(filepath.Join(rel, path)), qry, )) return &csv, err }
// InlineImage returns a base64 encoded png from the input image func InlineImage(mainctx context.Context, usv libsass.SassValue) (rsv *libsass.SassValue, err error) { var ( name string encode bool f io.ReadCloser ) comp, err := libsass.CompFromCtx(mainctx) if err != nil { return nil, err } err = libsass.Unmarshal(usv, &name, &encode) if err != nil { return nil, err } paths := comp.(libsass.Pather) // check for valid URL. If true, attempt to resolve image. // This is really going to slow down compilation think about // writing data to disk instead of inlining. u, err := url.Parse(name) if err == nil && len(u.Scheme) > 0 { f, err = imgResolver.Do(u.String()) } else { f, err = os.Open(filepath.Join(paths.ImgDir(), name)) } if err != nil { return nil, err } defer f.Close() var buf bytes.Buffer err = sw.Inline(f, &buf, encode) if err != nil { return nil, err } res, err := libsass.Marshal(buf.String()) if err != nil { return nil, err } return &res, nil }
// ImageURL handles calls to resolve the path to a local image from the // built css file path. func ImageURL(ctx context.Context, csv libsass.SassValue) (*libsass.SassValue, error) { comp, err := libsass.CompFromCtx(ctx) if err != nil { return nil, err } pather := comp.(libsass.Pather) var path []string err = libsass.Unmarshal(csv, &path) // This should create and throw a sass error if err != nil { return nil, err } if len(path) != 1 { return nil, errors.New("path not found") } imgdir := pather.ImgDir() abspath := filepath.Join(imgdir, path[0]) method := comp.CacheBust() qry, err := qs(method, abspath) if err != nil { return nil, err } rel, err := relativeImage(pather.BuildDir(), pather.ImgDir()) if err != nil { return nil, err } url := strings.Join([]string{ rel, path[0], }, "/") res, err := libsass.Marshal(fmt.Sprintf("url('%s%s')", url, qry)) if err != nil { return nil, err } return &res, nil }
// 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 }