mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-29 03:55:49 +01:00
Move screenshot encoding to PebbleProtocol
This commit is contained in:
parent
55cecceb38
commit
531aef61fd
@ -17,9 +17,13 @@
|
|||||||
package nodomain.freeyourgadget.gadgetbridge.deviceevents;
|
package nodomain.freeyourgadget.gadgetbridge.deviceevents;
|
||||||
|
|
||||||
public class GBDeviceEventScreenshot extends GBDeviceEvent {
|
public class GBDeviceEventScreenshot extends GBDeviceEvent {
|
||||||
public int width;
|
private final byte[] data;
|
||||||
public int height;
|
|
||||||
public byte bpp;
|
public GBDeviceEventScreenshot(final byte[] data) {
|
||||||
public byte[] clut;
|
this.data = data;
|
||||||
public byte[] data;
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -379,6 +379,11 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleGBDeviceEvent(GBDeviceEventScreenshot screenshot) {
|
private void handleGBDeviceEvent(GBDeviceEventScreenshot screenshot) {
|
||||||
|
if (screenshot.getData() == null) {
|
||||||
|
LOG.warn("Screnshot data is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd-hhmmss", Locale.US);
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd-hhmmss", Locale.US);
|
||||||
String filename = "screenshot_" + dateFormat.format(new Date()) + ".bmp";
|
String filename = "screenshot_" + dateFormat.format(new Date()) + ".bmp";
|
||||||
|
|
||||||
|
@ -27,6 +27,10 @@ import org.json.JSONObject;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -65,6 +69,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
|
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
public class PebbleProtocol extends GBDeviceProtocol {
|
public class PebbleProtocol extends GBDeviceProtocol {
|
||||||
@ -281,7 +286,12 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
boolean mEnablePebbleKit = false;
|
boolean mEnablePebbleKit = false;
|
||||||
boolean mAlwaysACKPebbleKit = false;
|
boolean mAlwaysACKPebbleKit = false;
|
||||||
private boolean mForceProtocol = false;
|
private boolean mForceProtocol = false;
|
||||||
private GBDeviceEventScreenshot mDevEventScreenshot = null;
|
|
||||||
|
private byte[] screenshotData = null;
|
||||||
|
private int screenshotWidth;
|
||||||
|
private int screenshotHeight;
|
||||||
|
private byte screenshotBpp;
|
||||||
|
private byte[] screenshotClut;
|
||||||
private int mScreenshotRemaining = -1;
|
private int mScreenshotRemaining = -1;
|
||||||
|
|
||||||
//monochrome black + white
|
//monochrome black + white
|
||||||
@ -1945,27 +1955,26 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private GBDeviceEventScreenshot decodeScreenshot(ByteBuffer buf, int length) {
|
private GBDeviceEventScreenshot decodeScreenshot(ByteBuffer buf, int length) {
|
||||||
if (mDevEventScreenshot == null) {
|
if (screenshotData == null) {
|
||||||
byte result = buf.get();
|
byte result = buf.get();
|
||||||
mDevEventScreenshot = new GBDeviceEventScreenshot();
|
|
||||||
int version = buf.getInt();
|
int version = buf.getInt();
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
mDevEventScreenshot.width = buf.getInt();
|
screenshotWidth = buf.getInt();
|
||||||
mDevEventScreenshot.height = buf.getInt();
|
screenshotHeight = buf.getInt();
|
||||||
|
|
||||||
if (version == 1) {
|
if (version == 1) {
|
||||||
mDevEventScreenshot.bpp = 1;
|
screenshotBpp = 1;
|
||||||
mDevEventScreenshot.clut = clut_pebble;
|
screenshotClut = clut_pebble;
|
||||||
} else {
|
} else {
|
||||||
mDevEventScreenshot.bpp = 8;
|
screenshotBpp = 8;
|
||||||
mDevEventScreenshot.clut = clut_pebbletime;
|
screenshotClut = clut_pebbletime;
|
||||||
}
|
}
|
||||||
|
|
||||||
mScreenshotRemaining = (mDevEventScreenshot.width * mDevEventScreenshot.height * mDevEventScreenshot.bpp) / 8;
|
mScreenshotRemaining = (screenshotWidth * screenshotHeight * screenshotBpp) / 8;
|
||||||
|
|
||||||
mDevEventScreenshot.data = new byte[mScreenshotRemaining];
|
screenshotData = new byte[mScreenshotRemaining];
|
||||||
length -= 13;
|
length -= 13;
|
||||||
}
|
}
|
||||||
if (mScreenshotRemaining == -1) {
|
if (mScreenshotRemaining == -1) {
|
||||||
@ -1973,26 +1982,68 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
}
|
}
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
byte corrected = buf.get();
|
byte corrected = buf.get();
|
||||||
if (mDevEventScreenshot.bpp == 1) {
|
if (screenshotBpp == 1) {
|
||||||
corrected = reverseBits(corrected);
|
corrected = reverseBits(corrected);
|
||||||
} else {
|
} else {
|
||||||
corrected = (byte) (corrected & 0b00111111);
|
corrected = (byte) (corrected & 0b00111111);
|
||||||
}
|
}
|
||||||
|
|
||||||
mDevEventScreenshot.data[mDevEventScreenshot.data.length - mScreenshotRemaining + i] = corrected;
|
screenshotData[screenshotData.length - mScreenshotRemaining + i] = corrected;
|
||||||
}
|
}
|
||||||
mScreenshotRemaining -= length;
|
mScreenshotRemaining -= length;
|
||||||
LOG.info("Screenshot remaining bytes " + mScreenshotRemaining);
|
LOG.info("Screenshot remaining bytes " + mScreenshotRemaining);
|
||||||
if (mScreenshotRemaining == 0) {
|
if (mScreenshotRemaining == 0) {
|
||||||
mScreenshotRemaining = -1;
|
mScreenshotRemaining = -1;
|
||||||
LOG.info("Got screenshot : " + mDevEventScreenshot.width + "x" + mDevEventScreenshot.height + " " + "pixels");
|
LOG.info("Got screenshot : " + screenshotWidth + "x" + screenshotHeight + " " + "pixels");
|
||||||
GBDeviceEventScreenshot devEventScreenshot = mDevEventScreenshot;
|
GBDeviceEventScreenshot devEventScreenshot = new GBDeviceEventScreenshot(encodeScreenshotBmp());
|
||||||
mDevEventScreenshot = null;
|
screenshotData = null;
|
||||||
return devEventScreenshot;
|
return devEventScreenshot;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte[] encodeScreenshotBmp() {
|
||||||
|
final int FILE_HEADER_SIZE = 14;
|
||||||
|
final int INFO_HEADER_SIZE = 40;
|
||||||
|
|
||||||
|
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||||
|
ByteBuffer headerbuf = ByteBuffer.allocate(FILE_HEADER_SIZE + INFO_HEADER_SIZE + screenshotClut.length);
|
||||||
|
headerbuf.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
|
// file header
|
||||||
|
headerbuf.put((byte) 'B');
|
||||||
|
headerbuf.put((byte) 'M');
|
||||||
|
headerbuf.putInt(0); // size in bytes (uncompressed = 0)
|
||||||
|
headerbuf.putInt(0); // reserved
|
||||||
|
headerbuf.putInt(FILE_HEADER_SIZE + INFO_HEADER_SIZE + screenshotClut.length);
|
||||||
|
|
||||||
|
// info header
|
||||||
|
headerbuf.putInt(INFO_HEADER_SIZE);
|
||||||
|
headerbuf.putInt(screenshotWidth);
|
||||||
|
headerbuf.putInt(-screenshotHeight);
|
||||||
|
headerbuf.putShort((short) 1); // planes
|
||||||
|
headerbuf.putShort((short) screenshotBpp);
|
||||||
|
headerbuf.putInt(0); // compression
|
||||||
|
headerbuf.putInt(0); // length of pixeldata in bytes (uncompressed=0)
|
||||||
|
headerbuf.putInt(0); // pixels per meter (x)
|
||||||
|
headerbuf.putInt(0); // pixels per meter (y)
|
||||||
|
headerbuf.putInt(screenshotClut.length / 4); // number of colors in CLUT
|
||||||
|
headerbuf.putInt(0); // numbers of used colors
|
||||||
|
headerbuf.put(screenshotClut);
|
||||||
|
baos.write(headerbuf.array());
|
||||||
|
int rowbytes = (screenshotWidth * screenshotBpp) / 8;
|
||||||
|
byte[] pad = new byte[rowbytes % 4];
|
||||||
|
for (int i = 0; i < screenshotHeight; i++) {
|
||||||
|
baos.write(screenshotData, rowbytes * i, rowbytes);
|
||||||
|
baos.write(pad);
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
} catch (final IOException e) {
|
||||||
|
LOG.warn("Failed to encode screenshot to bpm");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private GBDeviceEvent[] decodeAction(ByteBuffer buf) {
|
private GBDeviceEvent[] decodeAction(ByteBuffer buf) {
|
||||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
byte command = buf.get();
|
byte command = buf.get();
|
||||||
|
@ -347,44 +347,12 @@ public class GB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String writeScreenshot(GBDeviceEventScreenshot screenshot, String filename) throws IOException {
|
public static String writeScreenshot(GBDeviceEventScreenshot screenshot, String filename) throws IOException {
|
||||||
|
LOG.info("Will write screenshot as {}", filename);
|
||||||
|
|
||||||
LOG.info("Will write screenshot: " + screenshot.width + "x" + screenshot.height + "x" + screenshot.bpp + "bpp");
|
final File dir = FileUtils.getExternalFilesDir();
|
||||||
final int FILE_HEADER_SIZE = 14;
|
final File outputFile = new File(dir, filename);
|
||||||
final int INFO_HEADER_SIZE = 40;
|
|
||||||
|
|
||||||
File dir = FileUtils.getExternalFilesDir();
|
|
||||||
File outputFile = new File(dir, filename);
|
|
||||||
try (FileOutputStream fos = new FileOutputStream(outputFile)) {
|
try (FileOutputStream fos = new FileOutputStream(outputFile)) {
|
||||||
ByteBuffer headerbuf = ByteBuffer.allocate(FILE_HEADER_SIZE + INFO_HEADER_SIZE + screenshot.clut.length);
|
fos.write(screenshot.getData());
|
||||||
headerbuf.order(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
|
|
||||||
// file header
|
|
||||||
headerbuf.put((byte) 'B');
|
|
||||||
headerbuf.put((byte) 'M');
|
|
||||||
headerbuf.putInt(0); // size in bytes (uncompressed = 0)
|
|
||||||
headerbuf.putInt(0); // reserved
|
|
||||||
headerbuf.putInt(FILE_HEADER_SIZE + INFO_HEADER_SIZE + screenshot.clut.length);
|
|
||||||
|
|
||||||
// info header
|
|
||||||
headerbuf.putInt(INFO_HEADER_SIZE);
|
|
||||||
headerbuf.putInt(screenshot.width);
|
|
||||||
headerbuf.putInt(-screenshot.height);
|
|
||||||
headerbuf.putShort((short) 1); // planes
|
|
||||||
headerbuf.putShort((short) screenshot.bpp);
|
|
||||||
headerbuf.putInt(0); // compression
|
|
||||||
headerbuf.putInt(0); // length of pixeldata in bytes (uncompressed=0)
|
|
||||||
headerbuf.putInt(0); // pixels per meter (x)
|
|
||||||
headerbuf.putInt(0); // pixels per meter (y)
|
|
||||||
headerbuf.putInt(screenshot.clut.length / 4); // number of colors in CLUT
|
|
||||||
headerbuf.putInt(0); // numbers of used colors
|
|
||||||
headerbuf.put(screenshot.clut);
|
|
||||||
fos.write(headerbuf.array());
|
|
||||||
int rowbytes = (screenshot.width * screenshot.bpp) / 8;
|
|
||||||
byte[] pad = new byte[rowbytes % 4];
|
|
||||||
for (int i = 0; i < screenshot.height; i++) {
|
|
||||||
fos.write(screenshot.data, rowbytes * i, rowbytes);
|
|
||||||
fos.write(pad);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return outputFile.getAbsolutePath();
|
return outputFile.getAbsolutePath();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user