Page 1 of 2

[Solved!] Resizing screenshots so that they don't make my save files 10MB

Posted: Sat Oct 22, 2016 6:17 pm
by Rhinoceros
Hello, I am in the process of making save files for my game, and I want to make preview images for each save on the load screen. Relevant snippets:

save:

Code: Select all

local scrn = love.graphics.newScreenshot() -- gets the image data for a screenshot. This is unfortunate, because everything is drawn as 1080p and scaled down to whatever the resolution is. This means the string this generates is FRIGGIN' HUEG (save files are ~10MB, 1kb of which is actual save info, and the rest is HUEG SCRNSHOT)

local info = {
	scrndata = scrn:getString(), -- gets the string form of the 
	scrnw = scrn:getWidth(), -- width of the screenshot
	scrnh = scrn:getHeight() -- height of the screenshot
	}

info = Tserial.pack(info) -- pack the table to a string

name = "autosave" 

love.filesystem.write("saves/"..name..".rns",info)
The load function doesn't interact with the screenshot at all, but the setup function for the load screen uses this:

Code: Select all

local t = Tserial.unpack(love.filesystem.read("saves/"..v))

graphic = love.image.newImageData(t.scrnw, t.scrnh, t.scrndata)
To reconstruct the image.


The save files are enormous. 10MB save files to save two variables (which is all the game needs for a save/load right now). How can I scale the image data down to a much more reasonable size (1920x1080px -> 425x239px) for use as a thumbnail?

EDIT: I guess I should probably be using :encode() so that the image gets compressed as well, but that didn't occur to me until just now, and I'm not sure if it would work.

Re: Resizing screenshots so that they don't make my save files 10MB

Posted: Sat Oct 22, 2016 6:38 pm
by Nixola
That's actually how you're supposed to save image files.

Re: Resizing screenshots so that they don't make my save files 10MB

Posted: Sat Oct 22, 2016 6:46 pm
by pgimeno
If you really need to reduce the size, the only way I can think of is to draw it in resized form to a canvas and use [wiki]Canvas:newImageData[/wiki] to retrieve it.

Re: Resizing screenshots so that they don't make my save files 10MB

Posted: Sat Oct 22, 2016 7:00 pm
by Rhinoceros
Ok, yeah, they're compressed now to ~2000kb using :encode("png"). But for some reason, tserial doesn't like to load files with fileData in them. It doesn't return a table when I try to unpack it, and if I try to print the result tserial.unpack passes, it gives me invalid UTF-8 errors.

Re: Resizing screenshots so that they don't make my save files 10MB

Posted: Sat Oct 22, 2016 7:03 pm
by zorg
Here's how i'd do it:
- Internal canvas size of 1920x1080.
- Create a smaller canvas, like 100x100 or 160x90 or 160x100 or whatever.
- When saving the game, run this function:
- Set active canvas to the small one, and do lg.draw(internalCanvas, 0,0, 0, scalex, scaley) where the two scale params are previewDimensions/internalDimensions... this might mean that the saved screenshot is a frame behind, but that should not pose an issue.
- Get the small canvas' imagedata (Canvas:newImageData), encode that as 'png', receiving a FileData, which you can do :getString on, so you now have a string representation of the PNG image. combine it into your savefile, and it should be small enough.

I dont't think you need to store the preview image size this way.

Edit: I'd say that you could encode your image further into Base64, you wouldn't get UTF-8 decoding errors that way, but the fact is, i haven't found an -encoding- function in löve for that, only that FileData can be created from files having been encoded as base64... which doesn't help here.

Re: Resizing screenshots so that they don't make my save files 10MB

Posted: Sat Oct 22, 2016 7:21 pm
by Rhinoceros
Does this look right? I've never used canvases for anything before.

Code: Select all

	local scrn = love.graphics.newScreenshot() -- gets the image data for a screenshot

	local canvas = love.graphics.newCanvas(425,239) -- make a canvas that is the proper dimensions
	canvas:renderTo(function()
		love.graphics.setColor(255,255,255) -- set colour to white, i.e. draw normally
		love.graphics.draw(love.graphics.newImage(scrn),0,0, -- draw the screenshot at 0,0
		0, -- 0 rotation
		canvas:getWidth() / love.graphics.getWidth(), -- x scale
		canvas:getHeight() / love.graphics.getHeight() -- y scale
		)
	end)
	
	scrn = canvas:newImageData():encode("png") -- get the image data from the canvas and encode it as a png
Edit: fixed the y scale grabbing width instead of height of the window.

The file size is down to about 140kb now, so that's good.

Tserial is still giving me errors, though, so I might just have to give up on ramming images into save files and just have thumbnails be separate from the actual data.

Re: Resizing screenshots so that they don't make my save files 10MB

Posted: Sat Oct 22, 2016 7:39 pm
by zorg
You know, it might be just Tserial being unable to handle arbitrary string data... you could use a better serialization lib, like bitser for example.

Re: Resizing screenshots so that they don't make my save files 10MB

Posted: Sat Oct 22, 2016 8:00 pm
by Rhinoceros
Well, I'm not understanding bitser at all. do I use it in conjunction with Tserial, or can I put table in it? What functions do I use?

Re: Resizing screenshots so that they don't make my save files 10MB

Posted: Sat Oct 22, 2016 8:23 pm
by s-ol
Rhinoceros wrote:Well, I'm not understanding bitser at all. do I use it in conjunction with Tserial, or can I put table in it? What functions do I use?
you use bitser.dumps and bitser.loads to save/load tables into strings you can then store where/however you want.

Re: Resizing screenshots so that they don't make my save files 10MB

Posted: Sat Oct 22, 2016 8:50 pm
by Rhinoceros
s-ol wrote: you use bitser.dumps and bitser.loads to save/load tables into strings you can then store where/however you want.
Ahh, ok. I got it to serialize the save data, but if I try to put filedata in the table, it throws an error. How should I go about writing filedata to a file as part of a table?