ESP32(Arduino)BMP转RGB565后LVGL显示像素错位求助
基于ESP32的BMP转RGB565图像显示错位问题
正在开展一项基于ESP32的项目,ESP32从PHP页面获取经JPG转换而来的BMP图像,随后需将该BMP图像转为RGB565格式,以通过LVGL进行显示。经测试,显示模块与LVGL本身无异常(标准图像可正常展示),但转换后的图像虽可识别,彩色像素却出现随机错位的情况,而该BMP图像在Windows系统中查看完全正常。
PHP图像获取与转换代码
<?php // Function to make a request to the Mouser API and fetch the image function fetchAndConvertImage() { // API key for accessing the Mouser API $apiKey = 'MY_API_KEY'; // URL for making a request to the Mouser API $url = 'https://api.mouser.com/api/v1/search/keyword?apiKey=' . $apiKey; // Data to be sent in the request $requestData = array( 'SearchByKeywordRequest' => array( 'keyword' => 'Thermistor', 'records' => 0, 'startingRecord' => 0, 'searchOptions' => 'string', 'searchWithYourSignUpLanguage' => 'en' ) ); // Encode the data in JSON format $jsonData = json_encode($requestData); // Set up the options for the POST request $options = array( 'http' => array( 'method' => 'POST', 'header' => 'Content-Type: application/json', 'content' => $jsonData ) ); // Create a context for the request $context = stream_context_create($options); // Make the request to the Mouser API $response = file_get_contents($url, false, $context); // Decode the JSON response $responseData = json_decode($response, true); // Extract the image path from the response $imagePath = $responseData['SearchResults']['Parts'][0]['ImagePath']; // Read the image data from the specified URL $imageData = file_get_contents("$imagePath"); // Generate a unique file name $fileName = uniqid('image_', true) . '.bmp'; $filePath = __DIR__ . '/' . $fileName; // Get image dimensions $image = imagecreatefromstring($imageData); $width = imagesx($image); $height = imagesy($image); // Calculate row size including padding $rowSize = floor(($width * 3 + 3) / 4) * 4; // Each pixel is 3 bytes (RGB), and we need to ensure each row is a multiple of 4 bytes // BMP header $bmpHeader = pack('c', 0x42) . pack('c', 0x4D); // Signature BM $bmpHeader .= pack('V', 14 + 40 + ($rowSize * $height)); // File size $bmpHeader .= pack('v', 0) . pack('v', 0); // Reserved $bmpHeader .= pack('V', 14 + 40); // Data offset $bmpHeader .= pack('V', 40); // Header size $bmpHeader .= pack('V', $width); // Image width $bmpHeader .= pack('V', $height); // Image height $bmpHeader .= pack('v', 1); // Number of planes $bmpHeader .= pack('v', 24); // Bits per pixel $bmpHeader .= pack('V', 0); // Compression (0 = no compression) $bmpHeader .= pack('V', 0); // Image size (can be 0 when no compression) $bmpHeader .= pack('V', 0); // Horizontal resolution (pixels per meter) $bmpHeader .= pack('V', 0); // Vertical resolution (pixels per meter) $bmpHeader .= pack('V', 0); // Number of colors in the palette $bmpHeader .= pack('V', 0); // Number of important colors // Convert image data to BMP format $bmpData = ''; for ($y = $height - 1; $y >= 0; --$y) { for ($x = 0; $x < $width; ++$x) { $rgb = imagecolorat($image, $x, $y); $color = imagecolorsforindex($image, $rgb); $bmpData .= pack('C', $color['blue']); // Blue $bmpData .= pack('C', $color['green']); // Green $bmpData .= pack('C', $color['red']); // Red } // Add padding to ensure row size is a multiple of 4 bytes $paddingBytes = $rowSize - ($width * 3); $bmpData .= str_repeat(pack('C', 0), $paddingBytes); } // Save BMP file file_put_contents($filePath, $bmpHeader . $bmpData); // Free memory imagedestroy($image); // Return file name return $fileName; } // Call the function to fetch and convert the image $imagePath = fetchAndConvertImage(); echo "https://theyoungmaker.ddns.net/opencomponent/$imagePath"; ?>
ESP32图像获取与转换代码
bool getImageFromURL(String url) { http.begin(url); int httpCode = http.GET(); if (httpCode == HTTP_CODE_OK) { WiFiClient* stream = http.getStreamPtr(); size_t totalLen = http.getSize(); size_t len = totalLen; // Allocate buffer for the image data uint8_t* bmp_data = (uint8_t*)malloc(len); if (!bmp_data) { Serial.println("Failed to allocate memory for image data"); http.end(); return false; } // Read data into buffer size_t index = 0; while (http.connected() && (len > 0 || len == -1)) { size_t size = stream->available(); if (size) { int c = stream->readBytes((char*)(bmp_data + index), size); index += c; if (len > 0) { len -= c; } } delay(1); } // Parse BMP header if (bmp_data[0] != 'B' || bmp_data[1] != 'M') { Serial.println("Not a valid BMP file"); free(bmp_data); http.end(); return false; } uint32_t dataOffset = *((uint32_t*)(bmp_data + 10)); uint32_t width = *((uint32_t*)(bmp_data + 18)); uint32_t height = *((uint32_t*)(bmp_data + 22)); uint16_t bitsPerPixel = *((uint16_t*)(bmp_data + 28)); uint32_t compression = *((uint32_t*)(bmp_data + 30)); if (bitsPerPixel != 24 || compression != 0) { Serial.println("Unsupported BMP format"); free(bmp_data); http.end(); return false; } // Allocate buffer for the image data in 16-bit format (RGB565) size_t imgSize = width * height * 2; gui_img_nouveau_projet_png_data = (uint8_t*)malloc(imgSize); if (!gui_img_nouveau_projet_png_data) { Serial.println("Failed to allocate memory for image data"); free(bmp_data); http.end(); return false; } // Convert pixel data to 16-bit (RGB565) format uint8_t* src = bmp_data + dataOffset; uint16_t* dst = (uint16_t*)gui_img_nouveau_projet_png_data; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { uint8_t b = *src++; uint8_t g = *src++; uint8_t r = *src++; *dst++ = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); } // Skip padding bytes if any src += (4 - (width * 3) % 4) % 4; } // Set image descriptor data gui_img_nouveau_projet_png.header.always_zero = 0; gui_img_nouveau_projet_png.header.w = width; gui_img_nouveau_projet_png.header.h = height; gui_img_nouveau_projet_png.data_size = imgSize; gui_img_nouveau_projet_png.header.cf = LV_IMG_CF_TRUE_COLOR; gui_img_nouveau_projet_png.data = gui_img_nouveau_projet_png_data; free(bmp_data); http.end(); return true; } else { Serial.printf("HTTP GET failed, error: %s\n", http.errorToString(httpCode).c_str()); http.end(); return false; } }
图像对比
原图像:

显示后的图像:

不确定问题出在服务器端的JPG转BMP环节,还是ESP32端的BMP转RGB565环节,恳请提供相关见解与解决建议。
内容的提问来源于stack exchange,提问作者Loic Daigle
相关产品推荐
相关产品推荐

