bodmer / jpegdecoder Goto Github PK
View Code? Open in Web Editor NEWA JPEG decoder library
License: Other
A JPEG decoder library
License: Other
Can you please add library.json and library.properties files to your repository? This allows them to be available through the library manager in the arduino IDE and the platform io lib manager.
See this documentations:
http://docs.platformio.org/en/latest/librarymanager/config.html
https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification
Once you have added the files the platformio and arduino ide teams need to be asked to add your repository to their scanning job...
And here two examples:
https://github.com/squix78/esp8266-oled-ssd1306/blob/master/library.json
https://github.com/squix78/esp8266-oled-ssd1306/blob/master/library.properties
I am working on a project and using Jans jpeg decoding on arduino tutorial as a guide. I used his code for the sending, and receiving and your code for decoding. I am not using the arduino camera though. I am attempting to just simply send a picture that I took using my computer. It is a jpg file, I reduced the size to 640x480, and it starts sending and populating the image one pixel at a time, but once it gets about 25% done, it stops sending color pixels and just starts just populating with a repeated single pixel color boxes. BUT.....when I attempt to send an image that is in the example folder (the tiger.jpg) it works perfectly fine. The whole image gets recieved. Do you have any ideas to help me out??? I confirmed the image was not a progressive jpeg.
Hey Bodmer, may chance you make your library compatible with the ESP8266 version of the Arduino platform?
Hello,
i want use this library on Photon. It's like arduino programation. I already compiled without errors, but when i print to serial the buffer of the decoded image (Baboon), and i run imshow(baboon_decoded) on Matlab, i don't saw the real image of baboon...
It's possible that math operation go wrong on Photon? It's a ARM M3, 120Mhz, 128kb SRAM.
Thanks for your attention
Hi all,
Great library! you made a great job!
I'm having some issue when running JPG decoding from SPIFFS,
The same sketch running from SD card runs perfectly.
The same JPG image is on SD card and on spiffs.
What i'm seeing when calling jpegInfo() is that values are shifted down:
Width 0
Height 160
Components 128
and so on...
Picture is 160x128.
This is only happening when running sketch from SPIFFS.
The image is uploaded to SPIFFS via Arduino ESP8266 Sketch Data Upload tool.
I uploaded JPG image for reference.
Best Regards,
Nikola
Hi,
firstly thank you for that great library.
but i believe your library name should be JPEGDecoder+TFT Shower :)
because it seem libray don't do decode Only. decode and draw images on screen too.
and if i am correct(i hope not) it cannot do Decode Only...
am i right?
please say NO :) and point me where do i mistaken.
i found your library while i am looking library to decode PNG/BMP(or JPEG at least) image to use on my projects.
but my project don't include any TFT screen... so i stuck.
i searched in codes you wrote. i tried to take just decode part from JPEG_functions but no luck.
it's seems nested with tft draw functions.
i hope i am wrong(about library name) and you can prove i am wrong by showing me where the Only decoding part.
On operating systems that do not neuter filenames (i.e linux), JPEGDecoder.h will generate a compile error as it looks for "arduino.h" which does not exist.
In fact the include for "arduino.h" on line 23 does not seem to be necessary at all.
Line 39 in 4164a39
Is this still correct?
https://github.com/espressif/arduino-esp32/tree/master/libraries/SPIFFS
How to get an individual pixel's color?
Hello,
I could not use the existing tools online and offline to convert JPG files into the PROGMEM array.
Can you please specify which tool did you use to create the EagleEye, Baboon40, etc. and other H files you include in the example?
Thx!
Is there any example for resizing jpg file for display on TFT?
Thank you.
Hi all,
esp core version 2.4.1
arduino ide 1.8.6
JPEGDecoder 1.7.8 ( and clone of todays master branch )
in my project I have an arducam and a display connected.
what i want to do is read the jpeg image from arducam, convert it and display the image.
My missing part is the conversion from jpeg to the display format. i included the jpeg library ( nothing else ,i called nothing in the lib )
and get the following error messages when compiling.
could anybody give me a hint what went wrong ?
Line 11 in my code is the include of the jpeg library
snip
// Demo Code for Frickelboard1
// Do in a loop
// read image from Cam and put on Display
// read BMP180 (i2c) and print on Display
#include <Wire.h>
#include <ArduCAM.h>
#include <SPI.h>
#include <Adafruit_BMP085.h> // BMP180
#include <JPEGDecoder.h> // JPEG decoder library
Arduino: 1.8.6 Hourly Build 2018/03/02 12:25 (Linux), Board: "NodeMCU 1.0 (ESP-12E Module), 80 MHz, 4M (1M SPIFFS), v2 Lower Memory, Disabled, None, Only Sketch, 115200"
In file included from /home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/memory:81:0,
from /home/DEV/.arduino15/packages/esp8266/hardware/esp8266/2.4.1/cores/esp8266/FS.h:24,
from /home/DEV/ownCloud/Arduino/libraries/JPEGDecoder/src/JPEGDecoder.h:41,
from /home/DEV/ownCloud/Projects/HuSch/Frickelboard1/DemoCode/CamAndSensor2Display/CamAndSensor2Display.ino:11:
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/unique_ptr.h:260:29: error: macro "swap" requires 3 arguments, but only 2 given
swap(std::get<0>(_M_t), __p);
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/unique_ptr.h:266:27: error: macro "swap" requires 3 arguments, but only 1 given
swap(unique_ptr& __u) noexcept
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/unique_ptr.h:269:21: error: macro "swap" requires 3 arguments, but only 2 given
swap(_M_t, __u._M_t);
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/unique_ptr.h:447:29: error: macro "swap" requires 3 arguments, but only 2 given
swap(std::get<0>(_M_t), __p);
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/unique_ptr.h:457:27: error: macro "swap" requires 3 arguments, but only 1 given
swap(unique_ptr& __u) noexcept
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/unique_ptr.h:460:21: error: macro "swap" requires 3 arguments, but only 2 given
swap(_M_t, __u._M_t);
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/unique_ptr.h:483:28: error: macro "swap" passed 4 arguments, but takes just 3
unique_ptr<_Tp, _Dp>& __y) noexcept
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/unique_ptr.h:484:19: error: macro "swap" requires 3 arguments, but only 1 given
{ __x.swap(__y); }
^
In file included from /home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr.h:52:0,
from /home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/memory:82,
from /home/DEV/.arduino15/packages/esp8266/hardware/esp8266/2.4.1/cores/esp8266/FS.h:24,
from /home/DEV/ownCloud/Arduino/libraries/JPEGDecoder/src/JPEGDecoder.h:41,
from /home/DEV/ownCloud/Projects/HuSch/Frickelboard1/DemoCode/CamAndSensor2Display/CamAndSensor2Display.ino:11:
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:852:43: error: macro "swap" requires 3 arguments, but only 1 given
__shared_ptr(std::move(__r)).swap(*this);
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:860:41: error: macro "swap" requires 3 arguments, but only 1 given
__shared_ptr(std::move(__r)).swap(*this);
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:868:43: error: macro "swap" requires 3 arguments, but only 1 given
__shared_ptr(std::move(__r)).swap(*this);
^
Multiple libraries were found for "SD.h"
Used: /home/DEV/.arduino15/packages/esp8266/hardware/esp8266/2.4.1/libraries/SD
Not used: /home/DEV/Arduino/libraries/SD
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:876:43: error: macro "swap" requires 3 arguments, but only 1 given
__shared_ptr(std::move(__r)).swap(*this);
^
/home/DEV/arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:882:34: error: macro "swap" requires 3 arguments, but only 1 given
{ __shared_ptr().swap(*this); }
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:890:32: error: macro "swap" requires 3 arguments, but only 1 given
__shared_ptr(__p).swap(*this);
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:896:37: error: macro "swap" requires 3 arguments, but only 1 given
{ __shared_ptr(__p, __d).swap(*this); }
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:901:60: error: macro "swap" requires 3 arguments, but only 1 given
{ __shared_ptr(__p, __d, std::move(__a)).swap(*this); }
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:934:43: error: macro "swap" requires 3 arguments, but only 2 given
swap(__shared_ptr<_Tp, _Lp>& __other) noexcept
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:936:34: error: macro "swap" requires 3 arguments, but only 2 given
std::swap(_M_ptr, __other._M_ptr);
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:1145:66: error: macro "swap" passed 4 arguments, but takes just 3
swap(__shared_ptr<_Tp, _Lp>& __a, __shared_ptr<_Tp, _Lp>& __b) noexcept
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:1146:19: error: macro "swap" requires 3 arguments, but only 1 given
{ __a.swap(__b); }
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:1291:32: error: macro "swap" requires 3 arguments, but only 1 given
{ __weak_ptr().swap(*this); }
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:1294:27: error: macro "swap" requires 3 arguments, but only 1 given
swap(__weak_ptr& __s) noexcept
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:1296:30: error: macro "swap" requires 3 arguments, but only 2 given
std::swap(_M_ptr, __s._M_ptr);
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:1321:62: error: macro "swap" passed 4 arguments, but takes just 3
swap(__weak_ptr<_Tp, _Lp>& __a, __weak_ptr<_Tp, _Lp>& __b) noexcept
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr_base.h:1322:19: error: macro "swap" requires 3 arguments, but only 1 given
{ __a.swap(__b); }
^
In file included from /home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/memory:82:0,
from /home/DEV/.arduino15/packages/esp8266/hardware/esp8266/2.4.1/cores/esp8266/FS.h:24,
from /home/DEV/ownCloud/Arduino/libraries/JPEGDecoder/src/JPEGDecoder.h:41,
from /home/DEV/ownCloud/Projects/HuSch/Frickelboard1/DemoCode/CamAndSensor2Display/CamAndSensor2Display.ino:11:
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr.h:431:52: error: macro "swap" requires 3 arguments, but only 2 given
swap(shared_ptr<_Tp>& __a, shared_ptr<_Tp>& __b) noexcept
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr.h:432:19: error: macro "swap" requires 3 arguments, but only 1 given
{ __a.swap(__b); }
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr.h:517:48: error: macro "swap" requires 3 arguments, but only 2 given
swap(weak_ptr<_Tp>& __a, weak_ptr<_Tp>& __b) noexcept
^
/home/DEV/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/bits/shared_ptr.h:518:19: error: macro "swap" requires 3 arguments, but only 1 given
{ __a.swap(__b); }
^
exit status 1
Error compiling for board NodeMCU 1.0 (ESP-12E Module).
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
So I am trying to get JPEG Decoder to work with SdFat (either the original or your modified one) and I keep getting errors.
Is there something else that I need to do? (besides changing the user_config.h)?
Is there maybe a prior version that works with sdfat?
I am coding for the Arduino mega 2560.
If you need any other information tell me.
if I missed something basic forgive me but I am still a noob. :)
for reference the error I get when compiling in platformio.
I just compile an empty sketch with the libraries loaded.
#include <Arduino.h>
#include <SdFat.h>
#include <JPEGdecoder.h>
void setup() {
// put your setup code here, to run once:
}
void loop() {
// put your main code here, to run repeatedly:
}
this is the output.
.pio\libdeps\megaatmega2560\JPEGDecoder\src\JPEGdecoder.cpp:361:46: error: no matching function for call to 'SdFat::open(c
onst String&, const uint8_t&)'
File pInFile = SD.open( pFilename, FILE_READ);
^
In file included from .pio\libdeps\megaatmega2560\SdFat-master/utility/FatLib.h:24:0,
from .pio\libdeps\megaatmega2560\SdFat-master/SdFat.h:27,
from .pio\libdeps\megaatmega2560\JPEGDecoder\src\JPEGDecoder.h:54,
from .pio\libdeps\megaatmega2560\JPEGDecoder\src\JPEGdecoder.cpp:39:
.pio\libdeps\megaatmega2560\SdFat-master/utility/FatFileSystem.h:82:8: note: candidate: File FatFileSystem::open(const cha
r*, uint8_t)
File open(const char *path, uint8_t mode = FILE_READ) {
^
.pio\libdeps\megaatmega2560\SdFat-master/utility/FatFileSystem.h:82:8: note: no known conversion for argument 1 from 'co
nst String' to 'const char*'
*** [.pio\build\megaatmega2560\libbc9\JPEGDecoder\JPEGDecoder.cpp.o] Error 1
here is the config file
// Comment out the next #defines if you are not using an SD Card to store the JPEGs
// Commenting out the line is NOT essential but will save some FLASH space if
// SD Card access is not needed. Note: use of SdFat is currently untested!
//#define LOAD_SD_LIBRARY // Default SD Card library
#define LOAD_SDFAT_LIBRARY // Use SdFat library instead, so SD Card SPI can be bit bashed
// Note for ESP8266 users:
// If the sketch uses SPIFFS and has included FS.h without defining FS_NO_GLOBALS first
// then the JPEGDecoder library will NOT load the SD or SdFat libraries. Use lines thus
// in your sketch (see the examples included in the JPEGDecoder library):
/*
#define FS_NO_GLOBALS
#include <FS.h>
// You will then need to directly reference the SPIFFS File type thus in the sketch, e.g.:
fs::File jpegFile = SPIFFS.open( filename, "r"); // Example
// This will then allow the default method of using the SD library File type to be used
// in the same sketch, e.g.:
File jpegFile = SD.open( filename, FILE_READ);
*/
// This is all to avoid a redefinition of 'class fs::File' error due to a conflict between the
// duplicate definitions in the SD library and the SPIFFS library.
#ifdef ESP8266
// Uncomment out the next #define if you want the bytes swapped in the image blocks
// returned by read().
// Swapping the bytes is only needed to use the ESP8266 SPI library writePattern()
// member function and it is better to use readSwappedBytes() instead of read() in
// the sketch. Images will look psychedelic with wrong colours if the SPI transmit byte
// order is not right for your sketch!
// #define SWAP_BYTES // Deprecated, only included for backwards compatibility
#endif
I'm loading the image to display from a web server and would like to scale the image to fit the screen. Simple scaling by 1/2 or 1/4 would be sufficient.
#include <TFT_eSPI.h>
#include <SPI.h>
#include <WiFi.h>
#include <HTTPClient.h>
TFT_eSPI tft = TFT_eSPI();
const char* ssid = "****";
const char* password = "****";
// JPEG decoder library
#include <JPEGDecoder.h>
const int picBufferSize = 640*480;
void *picBuffer = NULL;
// Return the minimum of two values a and b
#define minimum(a,b) (((a) < (b)) ? (a) : (b))
//####################################################################################################
// Draw a JPEG on the TFT, images will be cropped on the right/bottom sides if they do not fit
//####################################################################################################
// This function assumes xpos,ypos is a valid screen coordinate. For convenience images that do not
// fit totally on the screen are cropped to the nearest MCU size and may leave right/bottom borders.
void renderJPEG(int xpos, int ypos) {
// retrieve infomration about the image
uint16_t *pImg;
uint16_t mcu_w = JpegDec.MCUWidth;
uint16_t mcu_h = JpegDec.MCUHeight;
uint32_t max_x = JpegDec.width;
uint32_t max_y = JpegDec.height;
// Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs)
// Typically these MCUs are 16x16 pixel blocks
// Determine the width and height of the right and bottom edge image blocks
uint32_t min_w = minimum(mcu_w, max_x % mcu_w);
uint32_t min_h = minimum(mcu_h, max_y % mcu_h);
// save the current image block size
uint32_t win_w = mcu_w;
uint32_t win_h = mcu_h;
// record the current time so we can measure how long it takes to draw an image
uint32_t drawTime = millis();
// save the coordinate of the right and bottom edges to assist image cropping
// to the screen size
max_x += xpos;
max_y += ypos;
// read each MCU block until there are no more
while (JpegDec.readSwappedBytes()) {
// save a pointer to the image block
pImg = JpegDec.pImage ;
// calculate where the image block should be drawn on the screen
int mcu_x = JpegDec.MCUx * mcu_w + xpos; // Calculate coordinates of top left corner of current MCU
int mcu_y = JpegDec.MCUy * mcu_h + ypos;
// check if the image block size needs to be changed for the right edge
if (mcu_x + mcu_w <= max_x) win_w = mcu_w;
else win_w = min_w;
// check if the image block size needs to be changed for the bottom edge
if (mcu_y + mcu_h <= max_y) win_h = mcu_h;
else win_h = min_h;
// copy pixels into a contiguous block
if (win_w != mcu_w)
{
uint16_t *cImg;
int p = 0;
cImg = pImg + win_w;
for (int h = 1; h < win_h; h++)
{
p += mcu_w;
for (int w = 0; w < win_w; w++)
{
*cImg = *(pImg + w + p);
cImg++;
}
}
}
// draw image MCU block only if it will fit on the screen
if (( mcu_x + win_w ) <= tft.width() && ( mcu_y + win_h ) <= tft.height())
{
tft.pushRect(mcu_x, mcu_y, win_w, win_h, pImg);
}
else if ( (mcu_y + win_h) >= tft.height()) JpegDec.abort(); // Image has run off bottom of screen so abort decoding
}
// calculate how long it took to draw the image
drawTime = millis() - drawTime;
// print the results to the serial port
Serial.print(F( "Total render time was : ")); Serial.print(drawTime); Serial.println(F(" ms"));
Serial.println(F(""));
}
//####################################################################################################
// Draw a JPEG on the TFT pulled from a program memory array
//####################################################################################################
void drawArrayJpeg(const uint8_t arrayname[], uint32_t array_size, int xpos, int ypos) {
int x = xpos;
int y = ypos;
JpegDec.decodeArray(arrayname, array_size);
renderJPEG(x, y);
Serial.println("#########################");
}
void setup(void) {
Serial.begin(115200);
tft.init();
tft.fillScreen(TFT_BLACK);
delay(10);
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
picBuffer = malloc(picBufferSize);
HTTPClient http;
http.begin("https://placebear.com/128/128"); //Specify the URL
int httpCode = http.GET(); //Make the request
if (httpCode > 0) { //Check for the returning code
//String payload = http.getString();
Serial.println(httpCode);
//Serial.println(payload);
int len = http.getSize();
Serial.printf("[HTTP] size: %d\n", len);
WiFiClient * stream = http.getStreamPtr();
// read all data from server
uint8_t* p = (uint8_t*) picBuffer;
int l = len;
while (http.connected() && (l > 0 || len == -1))
{
// get available data size
size_t size = stream->available();
if (size)
{
int c = stream->readBytes(p, size);
p += size;
Serial.printf("[HTTP] read: %d\n", c);
}
}
Serial.println();
Serial.print("[HTTP] connection closed.\n");
drawArrayJpeg((uint8_t*) picBuffer, len, 0, 16);
}
else {
Serial.println("Error on HTTP request");
}
http.end();
}
void loop(){
}
Arduino: 1.6.5 (Windows XP), Board: "Arduino Due (Programming Port)"
Build options changed, rebuilding all
WARNING: library TFT_HX8357 claims to run on [avr] architecture(s) and may be incompatible with your current board which runs on [sam] architecture(s).
TFT_SDcard_jpg_v1.ino: In function 'void loop()':
TFT_SDcard_jpg_v1:114: error: 'drawSdJpeg' was not declared in this scope
TFT_SDcard_jpg_v1:135: error: 'createArray' was not declared in this scope
TFT_SDcard_jpg_v1.ino: In function 'void drawSdJpeg(char*, int, int)':
TFT_SDcard_jpg_v1:149: error: 'renderJPEG' was not declared in this scope
TFT_SDcard_jpg_v1.ino: In function 'void renderJPEG(int, int)':
TFT_SDcard_jpg_v1:194: error: 'showTime' was not declared in this scope
TFT_SDcard_jpg_v1.ino: In function 'void createArray(const char*)':
TFT_SDcard_jpg_v1.ino:258:40: warning: converting to non-pointer type 'int' from NULL [-Wconversion-null]
Multiple libraries were found for "SPI.h"
Used: C:\Documents and Settings\So sory\Application Data\Arduino15\packages\arduino\hardware\sam\1.6.9\libraries\SPI
Not used: C:\Documents and Settings\So sory\My Documents\Arduino\libraries\SmingCore
'drawSdJpeg' was not declared in this scope
This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences.
Any cue to give me?
How to use it with your TFT Due lib?
Thanks.
can I rename "arduino.jpg", FILE_READ to the file my pictures are in?
also, can I replace if (SD.exists("arduino.jpg")) with my folder my picture are in
Hi Bodmer, I don't know what is happening with my code. Some image files doesn't decompress at all. In the middle of the image it stops. See this video on youtube you will understand what I mean.
On a clean install (version 1.8.9) using an ESP8266 board I get this error:
Sd2PinMap.h:524:2: error: #error Architecture or board not supported.
#error Architecture or board not supported
I'm using code that's worked fine in the past. I even tried to simply run the SPIFFS example (obviously installing your TFT_eSPI library) to no avail. Any advise?
Great work, I really like this lib. Its 100 times faster than the standard ST77xx lib for ESP8266.
One think should be added: Please document the limitation that progressive jpegs are not supported. It took me a while to figure out that that was my problem :)
This is my main loop.
void loop()
{
drawJpeg("/test1.jpg", 0, 0); //not progressive, can be displayed
delay(5000);
drawJpeg("/test2.jpg", 0, 0); //progressive, is not displayed
delay(5000);
}`
It think there is a small bug, Obviously JpegDec.decodeFsFile(filename);
returns true, even though decoding failed due to the progressive jpeg. The console produces irritating output (no error, but 0 render time, and all the meta information is from the previous file.)
===========================
Drawing file: /test1.jpg
===========================
===============
JPEG image info
===============
Width :300
Height :300
Components :1
MCU / row :19
MCU / col :19
Scan type :4
MCU width :16
MCU height :16
===============
Total render time was : 142 ms
=====================================
===========================
Drawing file: /test2.jpg
===========================
===============
JPEG image info
===============
Width :300
Height :300
Components :1
MCU / row :19
MCU / col :19
Scan type :4
MCU width :16
MCU height :16
===============
Total render time was : 0 ms
=====================================
As well known that ESP32 has dual cores, and Arduino code usually runs on core 1, is there any possibility to use both core 0 and 1 to decoding jpg to improve performance?
Hi, thanks for the nice library. I use your library in combination with the TFT_eSPI library and use the example made by you TFT_sPIFFS_jpeg.ino. Also tried the TFT_flash_jpg.ino example and operates okay however couldn't figure out how to create a valid formatted h file (no details on this) to add/change the example so I upload a jpeg file and use the SPIFFs example instead.
However, by running the modified example, the colors seems to be swapped, red = blue and blue = red. By changing your code at the JPEGDecoder::readSwappedBytes()
function, I get the correct colors. I swapped the variable names at the lines 216
and 218
in JPEGDecoder.cpp, blue points to red and red points to blue:
const uint8_t *pSrcB = image_info.m_pMCUBufR + src_ofs;
const uint8_t *pSrcG = image_info.m_pMCUBufG + src_ofs;
const uint8_t *pSrcR = image_info.m_pMCUBufB + src_ofs;
Hardware I have used:
Please add in JPEGDecoder.h for compatibility with TFT_eSPI for esp8266 in PlatformIO
#ifndef USER_SETUP_LOADED // Lets PlatformIO users define settings in platformio.ini
#include "User_Config.h"
#endif // USER_SETUP_LOADED
Example https://github.com/Bodmer/TFT_eSPI/blob/master/User_Setup_Select.h
I have smaller ips 80*160 rgb display and i cannot get decoder to work correctly. I can see that it draws 16x16 blocks but those are in somehow rnd order and messy. I'm using nodemcu_jpeg example
[env:esp32dev]
platform = https://github.com/platformio/platform-espressif32.git#feature/stage
board = esp32dev
framework = arduino
upload_speed = 921600
/*-------------------------------------------------------------------------------------------
examples /MCUFRIEND_kbv/ jpeg_kbv.ino
https://github.com/Bodmer/JPEGDecoder
-------------------------------------------------------------------------------------------*/
#include "Arduino.h"
// #include <Adafruit_GFX.h>
// #include <Adafruit_ST7735.h> // Hardware-specific library
// #define TFT_CS 5
// #define TFT_DC 4
// #define TFT_RST 15
// Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
#include "Adafruit_ILI9341.h" // Hardware-specific library
#include <Adafruit_GFX.h> // Core graphics library
#include <SPI.h>
#define TFT_CS 5
#define TFT_DC 4
#define TFT_RST 15
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
/*-------------------------------------------------------------------------------------------
xxx
-------------------------------------------------------------------------------------------*/
#include <JPEGDecoder.h>
#define minimum(a, b) (((a) < (b)) ? (a) : (b))
#include "jpeg1.h" // 测试图
void jpegInfo() {
Serial.println(F("==============="));
Serial.println(F("JPEG image info"));
Serial.println(F("==============="));
Serial.printf("Width : %d \n", JpegDec.width);
Serial.printf("Height : %d \n", JpegDec.height);
Serial.printf("Components : %d \n", JpegDec.comps);
Serial.printf("MCU / row : %d \n", JpegDec.MCUSPerRow);
Serial.printf("MCU / col : %d \n", JpegDec.MCUSPerCol);
Serial.printf("Scan type : %d \n", JpegDec.scanType);
Serial.printf("MCU width : %d \n", JpegDec.MCUWidth);
Serial.printf("MCU height : %d \n", JpegDec.MCUHeight);
Serial.println(F("==============="));
}
void jpegRender(int xpos, int ypos) {
// retrieve infomration about the image
uint16_t *pImg;
uint16_t mcu_w = JpegDec.MCUWidth;
uint16_t mcu_h = JpegDec.MCUHeight;
uint32_t max_x = JpegDec.width;
uint32_t max_y = JpegDec.height;
// Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs)
// Typically these MCUs are 16x16 pixel blocks
// Determine the width and height of the right and bottom edge image blocks
uint32_t min_w = minimum(mcu_w, max_x % mcu_w);
uint32_t min_h = minimum(mcu_h, max_y % mcu_h);
// save the current image block size
uint32_t win_w = mcu_w;
uint32_t win_h = mcu_h;
// record the current time so we can measure how long it takes to draw an image
uint32_t drawTime = millis();
// save the coordinate of the right and bottom edges to assist image cropping
// to the screen size
max_x += xpos;
max_y += ypos;
// read each MCU block until there are no more
while (JpegDec.read()) {
// save a pointer to the image block
pImg = JpegDec.pImage;
// calculate where the image block should be drawn on the screen
int mcu_x = JpegDec.MCUx * mcu_w + xpos;
int mcu_y = JpegDec.MCUy * mcu_h + ypos;
// check if the image block size needs to be changed for the right and bottom edges
if (mcu_x + mcu_w <= max_x)
win_w = mcu_w;
else
win_w = min_w;
if (mcu_y + mcu_h <= max_y)
win_h = mcu_h;
else
win_h = min_h;
// calculate how many pixels must be drawn
uint16_t mcu_pixels = win_w * win_h;
// draw image MCU block only if it will fit on the screen
if ((mcu_x + win_w) <= tft.width() && (mcu_y + win_h) <= tft.height()) {
// if ((mcu_x + win_w) <= 80 && (mcu_y + win_h) <= 80) {
// Now set a MCU bounding window on the TFT to push pixels into (x, y, x + width - 1, y + height - 1)
tft.setAddrWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1);
// Write all MCU pixels to the TFT window
while (mcu_pixels--)
tft.pushColor(*pImg++); // Send MCU buffer to TFT 16 bits at a time
// tft.pushColors(pImg, mcu_pixels, 1);
}
// Stop drawing blocks if the bottom of the screen has been reached,
// the abort function will close the file
else if ((mcu_y + win_h) >= tft.height())
JpegDec.abort();
}
// calculate how long it took to draw the image
drawTime = millis() - drawTime;
// print the results to the serial port
Serial.print("Total render time was : ");
Serial.print(drawTime);
Serial.println(" ms");
Serial.println("=====================================");
}
void drawArrayJpeg(const uint8_t arrayname[], uint32_t array_size, int xpos, int ypos) {
boolean decoded = JpegDec.decodeArray(arrayname, array_size);
if (decoded) {
// print information about the image to the serial port
jpegInfo();
// render the image onto the screen at given coordinates
jpegRender(xpos, ypos);
} else {
Serial.println("Jpeg file format not supported!");
}
}
/*-------------------------------------------------------------------------------------------
xxx
-------------------------------------------------------------------------------------------*/
void setup() {
Serial.begin(115200);
Serial.println("Tansys_>>");
// tft.initR(INITR_HALLOWING);
// // tft.setRotation(4);
// tft.fillScreen(ST77XX_RED);
// // tft.setCursor(10, 10);
tft.begin();
// tft.setRotation(1);
tft.fillScreen(ILI9341_RED);
tft.println("TFT_init...");
tft.printf("TFT_size >> %d * %d", tft.width(), tft.height());
tft.println("Ready...");
drawArrayJpeg(Baboon, sizeof(Baboon), 0, 0);
}
void loop() {
delay(10);
}
Are there rules to follow when resizing jpeg images? Best sizes, resolutions, etc...? I've resized several jpeg images and when using TFT-eSPI ui.drawJpeg I get "bleeding". The bleeding can take on several forms; I don't see a pattern. When the jpeg is viewed normally within Windows, the image looks normal. Bottom line, not sure what's causing the bleeding, so I'm not sure how to fix it.
This is an example of an original image:
And this is a snapshot of the image on the screen when displayed with ui.drawJpeg("/m12.jpg", 30, 90):
The Adafruit_GFX library has been updated and may no longer be compatible with this library.
If the example sketches for the Adafruit library no longer work for you then post details here please.
Hi Bodmer,
first of all, thank you for this fantastic lib.
I am using a 480x320 ILI9486 TFT display with a "blue pill", and I had the problem of largely increased flash and RAM usage because of the "new uint16_t[]" constructor in line 335 of the JPEG decoder.
As a solution, I replaced the mentioned line by declaring a static array uint16_t img[16*16];
, and I assigned the pImage
variable to this array. Here are the changes.
Now, using the TFT_flash_jpg_v2A.ino sketch, I have the problem that the last MCU block (right bottom 16x16 pixels) of each decoded image is corrupted, and funnily, it shows the same corrupted pixel block for each image. I tried to increase the newly introduced array size, but it didn't help.
Could you please check what am I doing wrong? Or is there maybe a small bug somewhere in the software?
Hi @Bodmer,
I´m trying to load some Jpeg images using the JPEG Decoder, Adafruit ILI9341 and Adafruit GFX Libraries. All images appears distorted at the right side. What could be wrong?
Hardware:
ESP32 + ILI9341
thanks.
Regards,
lcfelippe.
All images are messed up
Serial.println(("==============="));
Serial.println(("JPEG image info"));
Serial.println(("==============="));
Serial.print(("Width :")); Serial.println(JpegDec.width);
Serial.print(("Height :")); Serial.println(JpegDec.height);
Serial.print(("Components :")); Serial.println(JpegDec.comps);
Serial.print(("MCU / row :")); Serial.println(JpegDec.MCUSPerRow);
Serial.print(("MCU / col :")); Serial.println(JpegDec.MCUSPerCol);
Serial.print(("Scan type :")); Serial.println(JpegDec.scanType);
Serial.print(("MCU width :")); Serial.println(JpegDec.MCUWidth);
Serial.print(("MCU height :")); Serial.println(JpegDec.MCUHeight);
Serial.println(("==============="));
always show only zeros. I am sure that the array is a correct image. I use ESP8266 on Arduino 2.3.0 and can't update to 2.4.1 due to visualMicro plugin for visual studio and using Templates that work only with ms compiler. I read that it is a bug in Arduino Core, also there is a function drawRaw() that works, but I could not find it.
How do you read a folder the the jpeg is in?
// open the image file File jpgFile = SD.open( "arduino.jpg", FILE_READ);
Hi Bodmer...
I'm using your JPEGDecoder in a sketch, and you were nice enough to fix the JPEG artifact bug I was encountering, so here is another issue I hope you can help with.
When I run the JPEGDecoder in a stand-alone sketch, it works fine. But when I run it in my slightly more complex sketch, it resets the ESP8266.
I think I have isolated the problem to the jpegRender function (if I comment that out, no resets occur, but of course no image is displayed either).
Things I have tried:
o Running on just a ESP8266 dev board (Huzzah Feather and NodeMCU) and on a plain ESP8266-12F in my circuit (both are reset by the JPEGDecoder functions)
o Using different JPEG images (including your samples) and even very small JPEG images
Can I please give you my sketch for you to try and see if you can figure out why JPEGDecode is causing a reset?
Thank you!
hi
i tried to use ESP32_SDcard_jpeg.ino but all images appear with random blocks.
please see pictures attached
i changed sd, display, SPI_FREQUENCY (from 27 to 10) and picture definition. It does not work.
i'm using esp32 and a ili9341
i write this post here because i don't know if error is due to jpegdecoder or other
thanks for your help
I am trying to get your LIB to work with the PlaneSpotter Collor sketch. I saw on the PlaneSpotter page you had made some improvements.
Could you help me out on what to change in the PlaneSpotter sketch to make it work ?
My programming skills are not that good yet.
I now see the plane's, but the stay on the screen, and the map is missing.
The loading and refresh are better with you plugin, I can see that already.. :)
It's likely I've misunderstood an important point, but I'd like to ask something just in case it's not as dumb as it sounds. Have you thought about including a renderJpeg function in the JPEGDecoder library?
I have a few functions I carry to each new project and several are related to renderJpeg. I use them in conjunction with JPEGDecoder. In my mind I'd like to use the library to provide functionality to read and display jpeg files on a TFT-eSPI screen.
This is not a big deal, but something that I've always wished was a little different.
Hi Bodmer,
thank you one more time for the library and support. I did big improvements in my firmware.
The device i'm doing is driven by esp8266-12E and the screen is TFT ILI9341.
The goal for me now is as follows:
To do number 3. i need to sort out how to scroll/slide show the photos on the TFT screen every time i press the button. And it is a problem for me as so far i can see that to decode JPEG i need to pass file name (not surprised:)) to decoding method and then push it to the screen by tft.pushImage... The chosen image (by long button press) should be 'remembered' somehow in EEPROM and should be automatically displayed on the TFT screen next time the device is switched on.
So the problem i have is two fold:
For 1:
I was thinking to name the files like: 1.jpg, 2.jpg, 3.jpg... but i can't sort out how to construct the function to create strings(?) to 'make' a file names to be decoded. Is there any method in SPIFFS to distinguish between files without knowing their actual names? Like "next file" in SPIFFS instead of pointing to the file name?
For 2:
Is there a way to check the JPEG file address in SPIFFS memory so i can store this address in EEPROM instead of storing the string containing the file name? Or maybe it is the best approach to store the string and just pass the string as an argument to the decoding function on start up?
Thank you for any input:)
I'm trying to use JPEGDecoder to detect corrupted JPEG data. How could I do that?
My scenario: After capturing an image with an OV2640 camera and transmitting it via HTTP, I often get errors when decoding it with OpenCV. I already verified that it is caused by a hardware issue on the camera board.
Is there a simple way to determine if all JPEG blocks are valid?
What I mean with invalid JPEG: Corrupted image data, e.g. caused by missing bytes or flipped bits, yields a decoded image with shifted blocks and weirdly colored areas. In the bottom right there are usually several blocks filled with constant color. OpenCV fills them with plain gray, JPEGDecoder fills them with the last correctly decoded color.
I already tried to analyze if the last block is filled with constant color. But in certain situations this can be the case for correctly decoded images as well. I also looked into the source code to find a place where those unicolored pixels are set, but couldn't find it. The status returned by JPEGDecoder is not informative in this case.
Thanks for any hint into the right direction!
The JPEGDecoder::pjpeg_callback function is missing a return statement, even though the prototype says it returns a uchar. This return ends up in gCallbackStatus so it fails decode() with a random (stack garbage) error.
If the picture width isn't a exact fraction of the picture MCUWidth then these remaining pixels on the right side of the picture are shown disturbed.
For example, if picture width is 92 and MCUWidth is 16 then the remaining right border of 12 pixel width on the right side of the picture is disturbed.
Try it with the appended pic:
I did it with a Nodemcu ESP8266 Bord.
if i have gifs on a sd card and want to display them on a led matrix,will this decode the gif into rgb values to show the image on the led matrix?
Hi Bodmer,
I am working on a modified version of the PlaneSpotter (with your newest TFT lib) and I get a crash on decoding the jpeg map - see below.
The offending line is
while ( JpegDec.readSwappedBytes()) {
Any hints? thanks!
Exception 9: LoadStoreAlignmentCause: Load or store to an unaligned address
Decoding 50 results
0x40222864: TFT_eSPI::width() at /Users/Marc/Documents/Arduino/libraries/TFT_eSPI-master/TFT_eSPI.cpp line 2725
0x4020b8d6: PlaneSpotter::renderJPEG(int, int) at /Users/Marc/Documents/Arduino/builds/sketch/PlaneSpotter.cpp line 75 (discriminator 1)
0x4020b970: PlaneSpotter::drawSPIFFSJpeg(String, int, int) at /Users/Marc/Documents/Arduino/builds/sketch/PlaneSpotter.cpp line 54
0x4020c52e: ScreenPlaneSpotter::update() at /Users/Marc/Documents/Arduino/builds/sketch/ScreenPlaneSpotter.cpp line 84
Hello Bodmer.
Thank you for your useful library.
I found wrong code.
Line 348-367
And i use this library.
https://github.com/greiman/SdFat
next code don't work with this library..
File pInFile = SD.open( pFilename, FILE_READ);
Next code work with this library..
File pInFile;
pinFile = SD.open( pFilename, FILE_READ);
`#if defined (LOAD_SD_LIBRARY) || defined (LOAD_SDFAT_LIBRARY)
// Call specific to SD filing system in case leading / is used
int JPEGDecoder::decodeSdFile(const char *pFilename) {
File pInFile = SD.open( pFilename, FILE_READ);
return decodeSdFile(pInFile);
}
int JPEGDecoder::decodeSdFile(const String& pFilename) {
#if !defined (ARDUINO_ARCH_SAM)
File pInFile = SD.open( pFilename, FILE_READ);
return decodeSdFile(pInFile);
#else
return -1;
#endif
}`
Hi,
I'm interested in your project's source code and was wondering if you could add a license to it, in order to define the terms and conditions for the usage of this code.
As this page suggests it's best to request a license added to a project than to use unlicensed code at all.
JPEGDecoder/src/JPEGDecoder.cpp
Line 437 in 628752b
I was wondering if this line should be:
memset(pImage , 0 , image_info.m_MCUWidth * image_info.m_MCUHeight * sizeof(*pImage))
Thanks!
I am working on a project and using Jans jpeg decoding on arduino tutorial as a guide. I used his code for the sending, and receiving and your code for decoding. I am not using the arduino camera though. I am attempting to just simply send a picture that I took using my computer. It is a jpg file, I reduced the size to 640x480, and it starts sending and populating the image one pixel at a time, but once it gets about 25% done, it stops sending color pixels and just starts just populating with a repeated single pixel color boxes. BUT.....when I attempt to send an image that is in the example folder (the tiger.jpg) it works perfectly fine. The whole image gets recieved. Do you have any ideas to help me out??? I confirmed the image was not a progressive jpeg.
If the encoded jpeg has an MCU size of 8x8 then the file is rendered incorrectly.
The work-around is to always use jpeg files encoded with a 16x16 MCU size.
This is a bug I have not been able to track down, if anyone figures it out then let me know!
The MEGA2560 has got a whole 256kB of Flash. You can store several JPG images but these need to live at the "top" of Flash Memory i.e. after the executable code.
Regular PROGMEM goes to the "bottom" of Flash (just after the vector table)
This makes it easy for pgm_read_byte() to access 0-64kB of data.
But pgm_read_byte_far() can access all 0-256kB
Likewise, memcpy_PF() is the far version of memcpy_P()
This can put your JPG data after the code section.
#if defined(AVR)
#undef PROGMEM
#define PROGMEM __attribute__((section(".fini2")))
#endif
and this can make your sketch work with ESP8266, ESP32, ...
#if !defined(AVR)
#define uint_farptr_t uint8_t*
#define memcpy_PF memcpy_P
#define pgm_get_far_address
#endif
Your sketch will use pgm_get_far_address(x) and cast to uint_farptr_t for the JPG array in Flash.
And use memcpy_PF() to copy to SRAM.
JPEGs stored as byte arrays in Flash are limited to 32767 bytes by the AVR compiler.
There is no size limit for ARM, ESP, ...
Complex images will compress below 32kB. They render well. And you can fit several in Flash memory.
Yes, it makes Flash images practical for a Mega2560 or Xmega.
Redefining Preprocessor macros must be done with care. Most AVR programs only expect to use 0-64kB PROGMEM.
ARM and ESP targets do not have these problems.
David.
Hi @Bodmer
I am trying to use this library in my code ( not in Arduino environment) .
For now I am trying to test jpeg_kbv and convert the existing Baboon jpeg image data in jpeg1.h. I'm getting error number 18 ( status = 18 in locateSOSMarker). I'd appreciate if you can help me with that.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.