// Copyright (c) 2010 LearnBoost #pragma once #include #include "CanvasError.h" #include #include #include // node < 7 uses libstdc++ on macOS which lacks complete c++11 #ifdef HAVE_JPEG #include #include #endif #ifdef HAVE_GIF #include #if GIFLIB_MAJOR > 5 || GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1 #define GIF_CLOSE_FILE(gif) DGifCloseFile(gif, NULL) #else #define GIF_CLOSE_FILE(gif) DGifCloseFile(gif) #endif #endif #ifdef HAVE_RSVG #include // librsvg <= 2.36.1, identified by undefined macro, needs an extra include #ifndef LIBRSVG_CHECK_VERSION #include #endif #endif using JPEGDecodeL = std::function; class Image : public Napi::ObjectWrap { public: char *filename; int width, height; int naturalWidth, naturalHeight; Napi::Env env; static Napi::FunctionReference constructor; static void Initialize(Napi::Env& env, Napi::Object& target); Image(const Napi::CallbackInfo& info); Napi::Value GetComplete(const Napi::CallbackInfo& info); Napi::Value GetWidth(const Napi::CallbackInfo& info); Napi::Value GetHeight(const Napi::CallbackInfo& info); Napi::Value GetNaturalWidth(const Napi::CallbackInfo& info); Napi::Value GetNaturalHeight(const Napi::CallbackInfo& info); Napi::Value GetDataMode(const Napi::CallbackInfo& info); void SetDataMode(const Napi::CallbackInfo& info, const Napi::Value& value); void SetWidth(const Napi::CallbackInfo& info, const Napi::Value& value); void SetHeight(const Napi::CallbackInfo& info, const Napi::Value& value); static Napi::Value GetSource(const Napi::CallbackInfo& info); static void SetSource(const Napi::CallbackInfo& info); inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); } inline int stride(){ return cairo_image_surface_get_stride(_surface); } static int isPNG(uint8_t *data); static int isJPEG(uint8_t *data); static int isGIF(uint8_t *data); static int isSVG(uint8_t *data, unsigned len); static int isBMP(uint8_t *data, unsigned len); static cairo_status_t readPNG(void *closure, unsigned char *data, unsigned len); inline int isComplete(){ return COMPLETE == state; } cairo_surface_t *surface(); cairo_status_t loadSurface(); cairo_status_t loadFromBuffer(uint8_t *buf, unsigned len); cairo_status_t loadPNGFromBuffer(uint8_t *buf); cairo_status_t loadPNG(); void clearData(); #ifdef HAVE_RSVG cairo_status_t loadSVGFromBuffer(uint8_t *buf, unsigned len); cairo_status_t loadSVG(FILE *stream); cairo_status_t renderSVGToSurface(); #endif #ifdef HAVE_GIF cairo_status_t loadGIFFromBuffer(uint8_t *buf, unsigned len); cairo_status_t loadGIF(FILE *stream); #endif #ifdef HAVE_JPEG enum Orientation { NORMAL, MIRROR_HORIZ, MIRROR_VERT, ROTATE_180, ROTATE_90_CW, ROTATE_270_CW, MIRROR_HORIZ_AND_ROTATE_90_CW, MIRROR_HORIZ_AND_ROTATE_270_CW }; cairo_status_t loadJPEGFromBuffer(uint8_t *buf, unsigned len); cairo_status_t loadJPEG(FILE *stream); void jpegToARGB(jpeg_decompress_struct* args, uint8_t* data, uint8_t* src, JPEGDecodeL decode); cairo_status_t decodeJPEGIntoSurface(jpeg_decompress_struct *info, Orientation orientation); cairo_status_t decodeJPEGBufferIntoMimeSurface(uint8_t *buf, unsigned len); cairo_status_t assignDataAsMime(uint8_t *data, int len, const char *mime_type); class Reader { public: virtual bool hasBytes(unsigned n) const = 0; virtual uint8_t getNext() = 0; virtual void skipBytes(unsigned n) = 0; }; Orientation getExifOrientation(Reader& jpeg); void updateDimensionsForOrientation(Orientation orientation); void rotatePixels(uint8_t* pixels, int width, int height, int channels, Orientation orientation); #endif cairo_status_t loadBMPFromBuffer(uint8_t *buf, unsigned len); cairo_status_t loadBMP(FILE *stream); CanvasError errorInfo; void loaded(); cairo_status_t load(); ~Image(); enum { DEFAULT , LOADING , COMPLETE } state; enum data_mode_t { DATA_IMAGE = 1 , DATA_MIME = 2 } data_mode; typedef enum { UNKNOWN , GIF , JPEG , PNG , SVG } type; static type extension(const char *filename); private: cairo_surface_t *_surface; uint8_t *_data = nullptr; int _data_len; #ifdef HAVE_RSVG RsvgHandle *_rsvg; bool _is_svg; int _svg_last_width; int _svg_last_height; #endif };