-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WallPaper Image #140
base: master
Are you sure you want to change the base?
WallPaper Image #140
Conversation
The LICENSE of the uPNG lib is not compatible with Zeal's public domain license. A public domain / Creative Commons Zero / Zero-Clause BSD licensed PNG library implementation must be used for the library to be eligible to be merged to the OS repo. This could be done by finding one that has a compatible license, or to delete the existing library file(s) and begin reverse engineering a compatible-license PNG library from scratch. A simpler choice may be to instead make the software requiring a non-public-domain library to be a 'third-party' application, like ported emulators, living in its own separate repository at the Organization-level that can be optionally |
Good catch, I'll see what I can do. |
Why not use bitmap? Converting png to bitmap is effortless and bitmaps are also much easier to implement. |
It would be nice to have support for more used image formats. |
Not possible if they wanna comply with licenses |
It is very very possible, take stb libraries for example. There's stb_image with support for a lot of formats. |
stb_image does look like a good alternative. Otherwise maybe something like // Simplified PNG Reader in HolyC
CDC *PNGRead(U8 *filename) {
U8 *file_data;
I64 file_size;
U8 *ptr;
U8 *end;
U8 signature[8];
U64 chunk_length;
U8 chunk_type[4];
U8 *chunk_data;
U32 crc;
U64 width, height;
U8 bit_depth, color_type, compression_method, filter_method, interlace_method;
U8 *idat_data = NULL;
U64 idat_size = 0;
// Read the file
file_data = FileRead(filename, &file_size);
if (file_data == NULL) {
Print("Failed to read file: %s\n", filename);
return NULL;
}
ptr = file_data;
end = file_data + file_size;
// Step 1: Verify PNG signature
MemCopy(signature, ptr, 8);
ptr += 8;
if (MemCmp(signature, "\x89PNG\x0D\x0A\x1A\x0A", 8) != 0) {
Print("Invalid PNG signature\n");
Free(file_data);
return NULL;
}
// Step 2: Read chunks
while (ptr < end) {
// Read chunk length (big-endian)
if (ptr + 8 > end) break;
chunk_length = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
ptr += 4;
// Read chunk type
MemCopy(chunk_type, ptr, 4);
ptr += 4;
// Ensure we don't read beyond the file
if (ptr + chunk_length + 4 > end) {
Print("Unexpected end of file\n");
break;
}
chunk_data = ptr;
ptr += chunk_length;
// Read CRC (we'll skip CRC checking for simplicity)
crc = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
ptr += 4;
// Process chunk based on type
if (MemCmp(chunk_type, "IHDR", 4) == 0) {
// Process IHDR chunk
width = (chunk_data[0] << 24) | (chunk_data[1] << 16) | (chunk_data[2] << 8) | chunk_data[3];
height = (chunk_data[4] << 24) | (chunk_data[5] << 16) | (chunk_data[6] << 8) | chunk_data[7];
bit_depth = chunk_data[8];
color_type = chunk_data[9];
compression_method = chunk_data[10];
filter_method = chunk_data[11];
interlace_method = chunk_data[12];
// Only support 8-bit RGB images without interlacing
if (bit_depth != 8 || color_type != 2 || compression_method != 0 || filter_method != 0 || interlace_method != 0) {
Print("Unsupported PNG format\n");
Free(file_data);
return NULL;
}
} else if (MemCmp(chunk_type, "IDAT", 4) == 0) {
// Collect IDAT data
if (idat_data == NULL) {
idat_data = MAlloc(chunk_length);
idat_size = chunk_length;
MemCopy(idat_data, chunk_data, chunk_length);
} else {
// Concatenate data
U8 *new_data = MAlloc(idat_size + chunk_length);
MemCopy(new_data, idat_data, idat_size);
MemCopy(new_data + idat_size, chunk_data, chunk_length);
Free(idat_data);
idat_data = new_data;
idat_size += chunk_length;
}
} else if (MemCmp(chunk_type, "IEND", 4) == 0) {
// End of PNG
break;
} else {
// Skip other chunks
ptr += chunk_length + 4; // Skip chunk data and CRC
}
}
Free(file_data);
if (idat_data == NULL) {
Print("No image data found\n");
return NULL;
}
// Step 3: Decompress IDAT data using DEFLATE
// Since we cannot use licensed code, we'll implement a minimal DEFLATE decompressor
// For the sake of this example, let's assume a function DecompressDEFLATE exists
U8 *decompressed_data;
U64 decompressed_size;
decompressed_data = DecompressDEFLATE(idat_data, idat_size, &decompressed_size);
Free(idat_data);
if (decompressed_data == NULL) {
Print("Failed to decompress image data\n");
return NULL;
}
// Step 4: Process the decompressed data
// Remove filter bytes and reconstruct image data
U64 row_bytes = width * 3; // 3 bytes per pixel (RGB)
U8 *image_data = MAlloc(height * row_bytes);
U8 *src = decompressed_data;
U8 *dst = image_data;
for (U64 y = 0; y < height; y++) {
if (src >= decompressed_data + decompressed_size) {
Print("Unexpected end of decompressed data\n");
Free(decompressed_data);
Free(image_data);
return NULL;
}
U8 filter_type = *src++;
// For simplicity, only handle filter type 0 (None)
if (filter_type != 0) {
Print("Unsupported filter type: %d\n", filter_type);
Free(decompressed_data);
Free(image_data);
return NULL;
}
// Copy the scanline
MemCopy(dst, src, row_bytes);
src += row_bytes;
dst += row_bytes;
}
Free(decompressed_data);
// Step 5: Create CDC and plot pixels
CDC *dc = DCNew(width, height);
if (dc == NULL) {
Free(image_data);
return NULL;
}
dst = image_data;
for (U64 y = 0; y < height; y++) {
for (U64 x = 0; x < width; x++) {
U8 r = *dst++;
U8 g = *dst++;
U8 b = *dst++;
dc->color = BMP24Color(r, g, b, 0); // Assuming BMP24Color accepts RGB values
GrPlot(dc, x, y);
}
}
Free(image_data);
return dc;
} U8 *DecompressDEFLATE(U8 *data, U64 data_size, U64 *out_size) {
U8 *ptr = data;
U8 *end = data + data_size;
U8 *output = MAlloc(/* estimated output size */);
U64 output_pos = 0;
while (ptr < end) {
U8 bfinal = *ptr & 1;
U8 btype = (*ptr >> 1) & 0x03;
ptr++;
if (btype == 0) {
// Uncompressed block
if (ptr + 4 > end) break;
U16 len = ptr[0] | (ptr[1] << 8);
U16 nlen = ptr[2] | (ptr[3] << 8);
ptr += 4;
if (len != (~nlen & 0xFFFF)) {
Print("Invalid uncompressed block length\n");
Free(output);
return NULL;
}
if (ptr + len > end) {
Print("Unexpected end of data in uncompressed block\n");
Free(output);
return NULL;
}
MemCopy(output + output_pos, ptr, len);
output_pos += len;
ptr += len;
} else {
Print("Unsupported compression type\n");
Free(output);
return NULL;
}
if (bfinal) break;
}
*out_size = output_pos;
return output;
} CDC *BMPRead(U8 *filename) {
U8 *file_data;
I64 file_size;
U8 *ptr;
U64 width, height;
U16 bits_per_pixel;
U32 offset;
U8 *pixel_data;
// Read the file
file_data = FileRead(filename, &file_size);
if (file_data == NULL) {
Print("Failed to read file: %s\n", filename);
return NULL;
}
ptr = file_data;
// Check BMP signature ('BM')
if (ptr[0] != 'B' || ptr[1] != 'M') {
Print("Invalid BMP file\n");
Free(file_data);
return NULL;
}
// Read offset to pixel data
offset = ptr[10] | (ptr[11] << 8) | (ptr[12] << 16) | (ptr[13] << 24);
// Read DIB header (assuming BITMAPINFOHEADER)
width = ptr[18] | (ptr[19] << 8) | (ptr[20] << 16) | (ptr[21] << 24);
height = ptr[22] | (ptr[23] << 8) | (ptr[24] << 16) | (ptr[25] << 24);
bits_per_pixel = ptr[28] | (ptr[29] << 8);
if (bits_per_pixel != 24) {
Print("Unsupported BMP format (only 24-bit supported)\n");
Free(file_data);
return NULL;
}
pixel_data = file_data + offset;
// Create CDC and plot pixels
CDC *dc = DCNew(width, height);
if (dc == NULL) {
Free(file_data);
return NULL;
}
// BMP stores pixels bottom-up
for (U64 y = 0; y < height; y++) {
U8 *row = pixel_data + (height - 1 - y) * ((width * 3 + 3) & ~3);
for (U64 x = 0; x < width; x++) {
U8 b = *row++;
U8 g = *row++;
U8 r = *row++;
dc->color = BMP24Color(r, g, b, 0);
GrPlot(dc, x, y);
}
}
Free(file_data);
return dc;
} ^ ai generated, could be senseless lol |
Please don't use AI to generate code for obscure operating system. There are several flaws. Most important one is use of MAlloc without consideration to TempleOS's unique memory management. Temple uses heap allocator which isn't designed for large allocations. There is no garbage collection so memory fragmentation must be considered carefully. Large images could quickly exhaust heap. DecompressDEFLATE implementation is extremely naive and only handles uncompressed blocks. The code doesn't account for TempleOS color model. Temple uses specific 16 color palette so direct RGB conversion won't work properly. I suggest using memory-mapped files or fixed-size buffers. |
@SolsticeSpectrum it can work 32bit color can work. https://github.com/y4my4my4m/Zeal32BitPNGViewer The point of the code that I've shared was to give an idea of how it could be implemented manually without libraries. It wasn't meant to be used, more of a starting point if someone wants to pick it up. |
You can MAlloc entire gigabyte(s) allocations Garbage collection in TOS forks is just "don't forget to Free when you're done" Zeal is not TOS: i.e.: you can support 32 bit colors and the palette limitation is going to be deprecated some point in the next 100 years to use a 32bit color system that will deprecate the concept of palettes so don't get caught up on that Compression is banned in Zeal's Charter so no image formats that use compression should be bothered with |
From the Charter: "No encryption, No compression. All formats, files, protocols, and algorithms must operate entirely in unobfuscated plain-text. Decrypting, encrypting, decompressing, and compressing creates redundant overhead that makes programs slow and complicated. Encoding/decoding of unencrypted uncompressed data in binary formats (.ZXE, .BIN, .GR, .GR32, DolDoc sprite binary data, etc.) is permitted." |
I don't pretend to know whether PNG uses compression or not, but if it does, then it wouldn't be mainlined anyway |
So basically BMP is the best option |
Or, some new version of GR32, which would reduce the need for legacy cruft inherited from Microsoft |
https://github.com/Zeal-Operating-System/ZealOS/blob/master/src/Demo/Graphics/32BitPaint.ZC#L86 |
Problem with new image format is that it won't be easily convertable. For bmp I can use any online png to bmp converter. |
Given that GR32 (in its current form) is literally just raw framebuffer 32-bit RGB (and in some possible future version, may solely just have metadata for X and Y dimensions), it would be very easy to convert to anything else |
And similarly, any decent image library would have zero problem exporting out to a raw 32bit RGB bitmap representation of whatever image you may choose to throw at it |
The basic implemlentation is done.
A few things to fix: