Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Texture's LoadFromStream won't load pngs  (Read 2320 times)

0 Members and 1 Guest are viewing this topic.

JAssange

  • Full Member
  • ***
  • Posts: 104
    • View Profile
Texture's LoadFromStream won't load pngs
« on: August 25, 2011, 01:43:26 am »
I've been trying to write my own InputStream and testing trying to load png files. I eventually wrote a 'reference stream' which just loads the file as is to make sure it was working, and I discovered it seems loading anything except a png works fine, but I get an invalid header error if I load a png with it. Loading the png file with LoadFromFile works fine but I can't use that as I need a custom stream.
Here is my reference stream that works on everything (Fonts, .tgas, etc.) but not pngs:

Code: [Select]
#pragma once

#include <SFML/Graphics.hpp>

class ReferenceStream : public InputStream {
public:
ReferenceStream(string filename);
~ReferenceStream();
virtual Int64 Read(char* data, Int64 size);
    virtual Int64 Seek(Int64 position);
    virtual Int64 Tell();
    virtual Int64 GetSize();
private:
Int64 position;
char* buffer;
Int64 bufferLen;
};


Code: [Select]

#include "ReferenceStream.h"
#include <fstream>

ReferenceStream::ReferenceStream(string filename) : position(0), buffer(nullptr), bufferLen(-1) {
ifstream file(filename, ios::binary | ios::in);
// [snipped] App-specific error handling
file.seekg(0, ios::end);
bufferLen = (Int64)file.tellg();
file.seekg(0, ios::beg);
buffer = new char[(int)bufferLen];
memset(buffer, 0, sizeof(buffer));
file.read(buffer, bufferLen);
file.close();
}

Int64 ReferenceStream::Read(char* data, Int64 size) {
if (position + size > bufferLen) {
size = bufferLen - position;
}
for (Int64 i = position; i < (position + size); i++) {
data[i-position] = buffer[i];
}
return size;
}

Int64 ReferenceStream::Seek(Int64 position) {
this->position = position;
if (position >= bufferLen) {
this->position = bufferLen - 1;
}
return this->position;
}

Int64 ReferenceStream::Tell() {
return position;
}

Int64 ReferenceStream::GetSize() {
return bufferLen;
}

ReferenceStream::~ReferenceStream() {
delete[] buffer;
}


If I save the output of reading my full stream manually to a file it creates a valid png file, so a bug in SFML or stbimage is the only thing I can come up with...

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Texture's LoadFromStream won't load pngs
« Reply #1 on: August 25, 2011, 09:28:19 am »
Although I can't find what's wrong in your code, mine works perfectly.

Code: [Select]
class ReferenceStream2 : public InputStream
{
public:

    ReferenceStream2(string filename)
    {
       file = fopen(filename.c_str(), "rb");
    }

    ~ReferenceStream2()
    {
        fclose(file);
    }

    Int64 Read(char* data, Int64 size)
    {
        return fread(data, 1, size, file);
    }

    Int64 Seek(Int64 position)
    {
        return !fseek(file, position, SEEK_SET) ? Tell() : -1;
    }

    Int64 Tell()
    {
       return ftell(file);
    }

    Int64 GetSize()
    {
        Int64 position = Tell();
        fseek(file, 0, SEEK_END);
        Int64 size = Tell();
        Seek(position);
        return size;
    }

private:

   FILE* file;
};
Laurent Gomila - SFML developer

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Texture's LoadFromStream won't load pngs
« Reply #2 on: August 25, 2011, 09:33:31 am »
Maybe it's because of your Seek function that doesn't doesn't let the position go further than the end of the stream.

For image loading, I have to internally implement a eof() function, which is implemented like this:
Code: [Select]
bool eof(InputStream* stream)
{
    return stream->Tell() >= stream->GetSize();
}


It is important that the reading position can be at end + 1, implementations should never force it to be always valid (this is true for any kind of stream, not just sf::InputStream). With your class, Read() can never fail, one could read the last byte forever while thinking that he's advancing in the stream. And I think this is a mistake.
Laurent Gomila - SFML developer

JAssange

  • Full Member
  • ***
  • Posts: 104
    • View Profile
Texture's LoadFromStream won't load pngs
« Reply #3 on: August 25, 2011, 02:59:19 pm »
Found the problem. I wasn't advancing the current position in the file by the number of bytes read. I'm very surprised that anything was able to load without that... Anyway thanks for the help, your fread call was what made me realize what I was missing.