GLUSboolean GLUSAPIENTRY glusLoadTgaImage(const GLUSchar* filename, GLUStgaimage* tgaimage) { FILE* file; GLUSubyte type; GLUSubyte bitsPerPixel; size_t elementsRead; // check, if we have a valid pointer if (!filename || !tgaimage) { return GLUS_FALSE; } tgaimage->width = 0; tgaimage->height = 0; tgaimage->depth = 0; tgaimage->data = 0; tgaimage->format = 0; // open filename in "read binary" mode file = fopen(filename, "rb"); if (!file) { return GLUS_FALSE; } // seek through the tga header, up to the type: if(fseek(file, 2, SEEK_CUR)) { fclose(file); return GLUS_FALSE; } // read the type elementsRead = fread(&type, 1, 1, file); if (!glusCheckFileRead(file, elementsRead, 1)) { return GLUS_FALSE; } // check the type if (type != 2 && type != 10 && type != 11) { fclose(file); return GLUS_FALSE; } // seek through the tga header, up to the width/height: if(fseek(file, 9, SEEK_CUR)) { fclose(file); return GLUS_FALSE; } // read the width elementsRead = fread(&tgaimage->width, 2, 1, file); if (!glusCheckFileRead(file, elementsRead, 1)) { glusDestroyTgaImage(tgaimage); return GLUS_FALSE; } if (tgaimage->width > GLUS_MAX_DIMENSION) { glusDestroyTgaImage(tgaimage); return GLUS_FALSE; } // read the height elementsRead = fread(&tgaimage->height, 2, 1, file); if (!glusCheckFileRead(file, elementsRead, 1)) { glusDestroyTgaImage(tgaimage); return GLUS_FALSE; } if (tgaimage->height > GLUS_MAX_DIMENSION) { glusDestroyTgaImage(tgaimage); return GLUS_FALSE; } tgaimage->depth = 1; // read the bits per pixel elementsRead = fread(&bitsPerPixel, 1, 1, file); if (!glusCheckFileRead(file, elementsRead, 1)) { glusDestroyTgaImage(tgaimage); return GLUS_FALSE; } // check the pixel depth if (bitsPerPixel != 8 && bitsPerPixel != 24 && bitsPerPixel != 32) { fclose(file); return GLUS_FALSE; } else { tgaimage->format = GLUS_LUMINANCE; if (bitsPerPixel == 24) { tgaimage->format = GLUS_RGB; } else if (bitsPerPixel == 32) { tgaimage->format = GLUS_RGBA; } } // move file pointer to beginning of targa data if(fseek(file, 1, SEEK_CUR)) { fclose(file); glusDestroyTgaImage(tgaimage); return GLUS_FALSE; } // allocate enough memory for the targa data tgaimage->data = (GLUSubyte*) malloc((size_t)tgaimage->width * tgaimage->height * bitsPerPixel / 8); // verify memory allocation if (!tgaimage->data) { fclose(file); glusDestroyTgaImage(tgaimage); return GLUS_FALSE; } if (type == 2) { // read in the raw data elementsRead = fread(tgaimage->data, 1, (size_t)tgaimage->width * tgaimage->height * bitsPerPixel / 8, file); if (!glusCheckFileRead(file, elementsRead, (size_t)tgaimage->width * tgaimage->height * bitsPerPixel / 8)) { glusDestroyTgaImage(tgaimage); return GLUS_FALSE; } } else { // RLE encoded GLUSint pixelsRead = 0; while (pixelsRead < tgaimage->width * tgaimage->height) { GLUSubyte amount; elementsRead = fread(&amount, 1, 1, file); if (!glusCheckFileRead(file, elementsRead, 1)) { glusDestroyTgaImage(tgaimage); return GLUS_FALSE; } if (amount & 0x80) { GLUSint i; GLUSint k; amount &= 0x7F; amount++; // read in the rle data elementsRead = fread(&tgaimage->data[pixelsRead * bitsPerPixel / 8], 1, bitsPerPixel / 8, file); if (!glusCheckFileRead(file, elementsRead, bitsPerPixel / 8)) { glusDestroyTgaImage(tgaimage); return GLUS_FALSE; } for (i = 1; i < amount; i++) { for (k = 0; k < bitsPerPixel / 8; k++) { tgaimage->data[(pixelsRead + i) * bitsPerPixel / 8 + k] = tgaimage->data[pixelsRead * bitsPerPixel / 8 + k]; } } } else { amount &= 0x7F; amount++; // read in the raw data elementsRead = fread(&tgaimage->data[pixelsRead * bitsPerPixel / 8], 1, (size_t) amount * bitsPerPixel / 8, file); if (!glusCheckFileRead(file, elementsRead, (size_t) amount * bitsPerPixel / 8)) { glusDestroyTgaImage(tgaimage); return GLUS_FALSE; } } pixelsRead += amount; } } // swap the color if necessary if (bitsPerPixel == 24 || bitsPerPixel == 32) { glusSwapColorChannel(tgaimage->width, tgaimage->height, tgaimage->format, tgaimage->data); } // close the file fclose(file); return GLUS_TRUE; }
GLUSboolean GLUSAPIENTRY glusSaveTgaImage(const GLUSchar* filename, const GLUStgaimage* tgaimage) { FILE* file; GLUSubyte buffer[12]; GLUSubyte bitsPerPixel; size_t elementsWritten; GLUSubyte* data; // check, if we have a valid pointer if (!filename || !tgaimage) { return GLUS_FALSE; } // open filename in "write binary" mode file = fopen(filename, "wb"); if (!file) { return GLUS_FALSE; } switch (tgaimage->format) { case GLUS_ALPHA: case GLUS_LUMINANCE: bitsPerPixel = 8; break; case GLUS_RGB: bitsPerPixel = 24; break; case GLUS_RGBA: bitsPerPixel = 32; break; default: fclose(file); return GLUS_FALSE; } if (bitsPerPixel == 8) { buffer[2] = 3; } else { buffer[2] = 2; } // TGA header buffer[0] = 0; buffer[1] = 0; buffer[3] = 0; buffer[4] = 0; buffer[5] = 0; buffer[6] = 0; buffer[7] = 0; buffer[8] = 0; buffer[9] = 0; buffer[10] = 0; buffer[11] = 0; elementsWritten = fwrite(buffer, 1, 12, file); if (!glusCheckFileWrite(file, elementsWritten, 12)) { return GLUS_FALSE; } elementsWritten = fwrite(&tgaimage->width, 1, sizeof(tgaimage->width), file); if (!glusCheckFileWrite(file, elementsWritten, 2)) { return GLUS_FALSE; } elementsWritten = fwrite(&tgaimage->height, 1, sizeof(tgaimage->height), file); if (!glusCheckFileWrite(file, elementsWritten, 2)) { return GLUS_FALSE; } elementsWritten = fwrite(&bitsPerPixel, 1, sizeof(bitsPerPixel), file); if (!glusCheckFileWrite(file, elementsWritten, 1)) { return GLUS_FALSE; } buffer[0] = 0; elementsWritten = fwrite(buffer, 1, 1, file); if (!glusCheckFileWrite(file, elementsWritten, 1)) { return GLUS_FALSE; } data = malloc(tgaimage->width * tgaimage->height * bitsPerPixel / 8); if (!data) { fclose(file); return GLUS_FALSE; } memcpy(data, tgaimage->data, tgaimage->width * tgaimage->height * bitsPerPixel / 8); if (bitsPerPixel >= 24) { glusSwapColorChannel(tgaimage->width, tgaimage->height, tgaimage->format, data); } elementsWritten = fwrite(data, 1, tgaimage->width * tgaimage->height * bitsPerPixel / 8, file); free(data); if (!glusCheckFileWrite(file, elementsWritten, tgaimage->width * tgaimage->height * bitsPerPixel / 8)) { return GLUS_FALSE; } fclose(file); return GLUS_TRUE; }