Save a cropped image in .bmp format in Xamarin c# - xamarin

Hi i m new to xamarin forms and i have an app that allows you to take a picture through camera and then i have given a rectangular box for cropping the captured image...i have written code for xamarin android and all this works fine and i can finally save the image as JPG or PNG as well.
But i want to save the final image as a .bmp file.
private void SaveOutput(Bitmap croppedImage)
{
if (saveUri != null)
{
try
{
using var outputStream = ContentResolver.OpenOutputStream(saveUri);
if (outputStream != null)
{
croppedImage.Compress(Bitmap.CompressFormat.Jpeg, 75, outputStream);
}
}
In this function, the croppedImage bitmap is getting compressed to jpg.
Instead of that i want to save that bitmap as a .bmp file.i have looked alot, but havent found any solution yet.
Can someone please suggest what i can do.

Here is a similar issue with native Android . You could convert the solution to C# like following
public class AndroidBmpUtil
{
private readonly int BMP_WIDTH_OF_TIMES = 4;
private readonly int BYTE_PER_PIXEL = 3;
/**
* Android Bitmap Object to Window's v3 24bit Bmp Format File
* #param orgBitmap
* #param filePath
* #return file saved result
*/
public bool Save(Bitmap orgBitmap, string filePath)
{
if (orgBitmap == null)
{
return false;
}
if (filePath == null)
{
return false;
}
var isSaveSuccess = true;
//image size
var width = orgBitmap.Width;
var height = orgBitmap.Height;
//image dummy data size
//reason : bmp file's width equals 4's multiple
var dummySize = 0;
byte[] dummyBytesPerRow = null;
var hasDummy = false;
if (isBmpWidth4Times(width))
{
hasDummy = true;
dummySize = BMP_WIDTH_OF_TIMES - width%BMP_WIDTH_OF_TIMES;
dummyBytesPerRow = new byte[dummySize*BYTE_PER_PIXEL];
for (var i = 0; i < dummyBytesPerRow.Length; i++)
{
dummyBytesPerRow[i] = 0xFF;
}
}
var pixels = new int[width*height];
var imageSize = pixels.Length*BYTE_PER_PIXEL + height*dummySize*BYTE_PER_PIXEL;
var imageDataOffset = 0x36;
var fileSize = imageSize + imageDataOffset;
//Android Bitmap Image Data
orgBitmap.GetPixels(pixels, 0, width, 0, 0, width, height);
//ByteArrayOutputStream baos = new ByteArrayOutputStream(fileSize);
var buffer = ByteBuffer.Allocate(fileSize);
try
{
/**
* BITMAP FILE HEADER Write Start
**/
buffer.Put(0x42);
buffer.Put(0x4D);
//size
buffer.Put(WriteInt(fileSize));
//reserved
buffer.Put(WriteShort(0));
buffer.Put(WriteShort(0));
//image data start offset
buffer.Put(WriteInt(imageDataOffset));
/** BITMAP FILE HEADER Write End */
//*******************************************
/** BITMAP INFO HEADER Write Start */
//size
buffer.Put(WriteInt(0x28));
//width, height
buffer.Put(WriteInt(width));
buffer.Put(WriteInt(height));
//planes
buffer.Put(WriteShort(1));
//bit count
buffer.Put(WriteShort(24));
//bit compression
buffer.Put(WriteInt(0));
//image data size
buffer.Put(WriteInt(imageSize));
//horizontal resolution in pixels per meter
buffer.Put(WriteInt(0));
//vertical resolution in pixels per meter (unreliable)
buffer.Put(WriteInt(0));
buffer.Put(WriteInt(0));
buffer.Put(WriteInt(0));
/** BITMAP INFO HEADER Write End */
var row = height;
var col = width;
var startPosition = 0;
var endPosition = 0;
while (row > 0)
{
startPosition = (row - 1)*col;
endPosition = row*col;
for (var i = startPosition; i < endPosition; i++)
{
buffer.Put(Write24BitForPixcel(pixels[i]));
if (hasDummy)
{
if (isBitmapWidthLastPixcel(width, i))
{
buffer.Put(dummyBytesPerRow);
}
}
}
row--;
}
var fos = new FileOutputStream(filePath);
fos.Write(new byte[buffer.Remaining()]);
fos.Close();
}
catch (Exception e1)
{
isSaveSuccess = false;
}
finally
{
}
return isSaveSuccess;
}
/**
* Is last pixel in Android Bitmap width
* #param width
* #param i
* #return
*/
private bool isBitmapWidthLastPixcel(int width, int i)
{
return i > 0 && i%(width - 1) == 0;
}
/**
* BMP file is a multiples of 4?
* #param width
* #return
*/
private bool isBmpWidth4Times(int width)
{
return width%BMP_WIDTH_OF_TIMES > 0;
}
/**
* Write integer to little-endian
* #param value
* #return
* #throws IOException
*/
private byte[] WriteInt(int value)
{
var b = new byte[4];
b[0] = (byte) (value & 0x000000FF);
b[1] = (byte) ((value & 0x0000FF00) >> 8);
b[2] = (byte) ((value & 0x00FF0000) >> 16);
b[3] = (byte) ((value & 0xFF000000) >> 24);
return b;
}
/**
* Write integer pixel to little-endian byte array
* #param value
* #return
* #throws IOException
*/
private byte[] Write24BitForPixcel(int value)
{
var
b = new byte[3];
b[0] = (byte) (value & 0x000000FF);
b[1] = (byte) ((value & 0x0000FF00) >> 8);
b[2] = (byte) ((value & 0x00FF0000) >> 16);
return b;
}
/**
* Write short to little-endian byte array
* #param value
* #return
* #throws IOException
*/
private byte[] WriteShort(short value)
{
var
b = new byte[2];
b[0] = (byte) (value & 0x00FF);
b[1] = (byte) ((value & 0xFF00) >> 8);
return b;
}
}

Related

mirror image the captured photo

I am clicking the picture and the passing it through intent. But the image that I am displaying on the ImageView is the mirror image of the image captured. I have tried to implement RotateFlip method but the error appears saying Bitmap doesn't contain definition of RotateFlip.
{
var metrics = Resources.DisplayMetrics;
int windowWidth = metrics.WidthPixels;
int windowHeight = metrics.HeightPixels;
int reqWidth = (int)Math.Round(windowWidth*1.0f);
int reqHeight = (int)Math.Round(windowHeight*1.0f);
Bitmap photo = loadBitmapLowResolution(Image, reqWidth, reqHeight);
ExifInterface exif = new ExifInterface(Image);
int orientation = exif.GetAttributeInt(ExifInterface.TagOrientation, 90);
var rotation = exif.GetAttributeInt(ExifInterface.TagOrientation, (int)Orientation.Normal);
orientation = exif.GetAttributeInt(ExifInterface.TagOrientation, (int)Orientation.Rotate90);
// Rotate according to the orientation
Matrix matrix = new Matrix();
switch (orientation)
{
case (int)Orientation.Rotate90: matrix.PostRotate(90); break;
case (int)Orientation.Rotate180: matrix.PostRotate(180); break;
case (int)Orientation.Rotate270: matrix.PostRotate(270); break;
}
Bitmap photoRotated;
if (orientation != (int)Orientation.Normal)
{
photoRotated = Bitmap.CreateBitmap(photo, 0, 0, photo.Width, photo.Height, matrix, true);
}
else
{
photoRotated = photo;
}
// Apply center crop
int cropW = (int)(0.5 * (photoRotated.Width - photoRotated.Width/1.0f ) - 2);
int cropH = (int)(0.5 * (photoRotated.Height - photoRotated.Height/1.0f ) - 2);
cropW = cropW < 0 ? 0 : cropW;
cropH = cropH < 0 ? 0 : cropH;
//Log.Debug(TAG, "Creating a bitmap with size: " + (photoRotated.Width - 2 * cropW) + "x" + (photoRotated.Height - 2 * cropH) + " from a bitmap with size: " + photoRotated.Width + "x" + photoRotated.Height);
Bitmap photoCrop = Bitmap.CreateBitmap(photoRotated, cropW, cropH, photoRotated.Width - 2 * cropW, photoRotated.Height- 2 * cropH);
imageView.SetImageBitmap(photoCrop);
// Create your application here,
}
public static Bitmap loadBitmapLowResolution(string filePath, int reqWidth, int reqHeight)
{
BitmapFactory.Options options = new BitmapFactory.Options();
// First decode with inJustDecodeBounds=true to check dimensions
options.InJustDecodeBounds = true;
BitmapFactory.DecodeFile(filePath, options);
// Calculate inSampleSize
options.InSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.InJustDecodeBounds = false;
return BitmapFactory.DecodeFile(filePath, options);
}
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight)
{
int height = options.OutHeight;
int width = options.OutWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth)
{
// Calculate ratios of height and width to requested height and width
int heightRatio = (int)Math.Round((float)height / (float)reqHeight);
int widthRatio = (int)Math.Round((float)width / (float)reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
The easiest way is to do it is using a Matrix;
public Bitmap HorizontalFlip(Bitmap bInput)
{
if (bInput == null) return null;
Matrix matrix = new Matrix();
matrix.PreScale(-1.0f, 1.0f);
return Bitmap.CreateBitmap(bInput, 0, 0, bInput.Width, bInput.Height, matrix, true);
}
Where bInput is the input bitmap that you wanna flip.

Libgdx loader for Animation.class

I need to set loader in assetmanager for Animation.class, i used Gifloader,that loads completly animation from GifDecoder(that creates animation from gif)
but get error:
https://i.stack.imgur.com/HkrWe.png
, error on build: https://i.stack.imgur.com/2Mpaz.png
setloader line:
manager.setLoader(Animation.class, new Gifloader(new InternalFileHandleResolver()))
Gifloader class:
package com.mygdx.testgame;
import com.badlogic.gdx.assets.AssetDescriptor;
import com.badlogic.gdx.assets.AssetLoaderParameters;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.assets.loaders.AsynchronousAssetLoader;
import com.badlogic.gdx.assets.loaders.FileHandleResolver;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.Array;
public class Gifloader extends AsynchronousAssetLoader<Animation<TextureRegion>, Gifloader.GifloaderParameter> {
private com.badlogic.gdx.graphics.g2d.Animation<TextureRegion> animresult;
public Gifloader(FileHandleResolver resolver) {
super(resolver);
}
#Override
public void loadAsync(AssetManager manager, String fileName, FileHandle file, GifloaderParameter parameter) {
animresult = (com.holidaystudios.tools.GifDecoder.loadGIFAnimation(Animation.PlayMode.LOOP,file.read()));
}
#Override
public Animation loadSync(AssetManager manager, String fileName, FileHandle file, GifloaderParameter parameter) {
return animresult;
}
#Override
public Array<AssetDescriptor> getDependencies(String fileName, FileHandle file, GifloaderParameter parameter) {
return null;
}
static public class GifloaderParameter extends AssetLoaderParameters<Animation<TextureRegion>> {
}
}
GifDecoder class:
/* Copyright by Johannes Borchardt */
/* LibGdx conversion 2014 by Anton Persson */
/* Released under Apache 2.0 */
/* https://code.google.com/p/animated-gifs-in-android/ */
package com.holidaystudios.tools;
import java.io.InputStream;
import java.util.Vector;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.Animation.PlayMode;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.utils.Array;
public class GifDecoder {
/**
* File read status: No errors.
*/
public static final int STATUS_OK = 0;
/**
* File read status: Error decoding file (may be partially decoded)
*/
public static final int STATUS_FORMAT_ERROR = 1;
/**
* File read status: Unable to open source.
*/
public static final int STATUS_OPEN_ERROR = 2;
/** max decoder pixel stack size */
protected static final int MAX_STACK_SIZE = 4096;
protected InputStream in;
protected int status;
protected int width; // full image width
protected int height; // full image height
protected boolean gctFlag; // global color table used
protected int gctSize; // size of global color table
protected int loopCount = 1; // iterations; 0 = repeat forever
protected int[] gct; // global color table
protected int[] lct; // local color table
protected int[] act; // active color table
protected int bgIndex; // background color index
protected int bgColor; // background color
protected int lastBgColor; // previous bg color
protected int pixelAspect; // pixel aspect ratio
protected boolean lctFlag; // local color table flag
protected boolean interlace; // interlace flag
protected int lctSize; // local color table size
protected int ix, iy, iw, ih; // current image rectangle
protected int lrx, lry, lrw, lrh;
protected DixieMap image; // current frame
protected DixieMap lastPixmap; // previous frame
protected byte[] block = new byte[256]; // current data block
protected int blockSize = 0; // block size last graphic control extension info
protected int dispose = 0; // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev
protected int lastDispose = 0;
protected boolean transparency = false; // use transparent color
protected int delay = 0; // delay in milliseconds
protected int transIndex; // transparent color index
// LZW decoder working arrays
protected short[] prefix;
protected byte[] suffix;
protected byte[] pixelStack;
protected byte[] pixels;
protected Vector<GifFrame> frames; // frames read from current file
protected int frameCount;
private static class DixieMap extends Pixmap {
DixieMap(int w, int h, Pixmap.Format f) {
super(w, h, f);
}
DixieMap(int[] data, int w, int h, Pixmap.Format f) {
super(w, h, f);
int x, y;
for(y = 0; y < h; y++) {
for(x = 0; x < w; x++) {
int pxl_ARGB8888 = data[x + y * w];
int pxl_RGBA8888 =
((pxl_ARGB8888 >> 24) & 0x000000ff) | ((pxl_ARGB8888 << 8) & 0xffffff00);
// convert ARGB8888 > RGBA8888
drawPixel(x, y, pxl_RGBA8888);
}
}
}
void getPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height) {
java.nio.ByteBuffer bb = getPixels();
int k, l;
for(k = y; k < y + height; k++) {
int _offset = offset;
for(l = x; l < x + width; l++) {
int pxl = bb.getInt(4 * (l + k * width));
// convert RGBA8888 > ARGB8888
pixels[_offset++] = ((pxl >> 8) & 0x00ffffff) | ((pxl << 24) & 0xff000000);
}
offset += stride;
}
}
}
private static class GifFrame {
public GifFrame(DixieMap im, int del) {
image = im;
delay = del;
}
public DixieMap image;
public int delay;
}
/**
* Gets display duration for specified frame.
*
* #param n
* int index of frame
* #return delay in milliseconds
*/
public int getDelay(int n) {
delay = -1;
if ((n >= 0) && (n < frameCount)) {
delay = frames.elementAt(n).delay;
}
return delay;
}
/**
* Gets the number of frames read from file.
*
* #return frame count
*/
public int getFrameCount() {
return frameCount;
}
/**
* Gets the first (or only) image read.
*
* #return BufferedPixmap containing first frame, or null if none.
*/
public Pixmap getPixmap() {
return getFrame(0);
}
/**
* Gets the "Netscape" iteration count, if any. A count of 0 means repeat indefinitely.
*
* #return iteration count if one was specified, else 1.
*/
public int getLoopCount() {
return loopCount;
}
/**
* Creates new frame image from current data (and previous frames as specified by their disposition codes).
*/
protected void setPixels() {
// expose destination image's pixels as int array
int[] dest = new int[width * height];
// fill in starting image contents based on last image's dispose code
if (lastDispose > 0) {
if (lastDispose == 3) {
// use image before last
int n = frameCount - 2;
if (n > 0) {
lastPixmap = getFrame(n - 1);
} else {
lastPixmap = null;
}
}
if (lastPixmap != null) {
lastPixmap.getPixels(dest, 0, width, 0, 0, width, height);
// copy pixels
if (lastDispose == 2) {
// fill last image rect area with background color
int c = 0;
if (!transparency) {
c = lastBgColor;
}
for (int i = 0; i < lrh; i++) {
int n1 = (lry + i) * width + lrx;
int n2 = n1 + lrw;
for (int k = n1; k < n2; k++) {
dest[k] = c;
}
}
}
}
}
// copy each source line to the appropriate place in the destination
int pass = 1;
int inc = 8;
int iline = 0;
for (int i = 0; i < ih; i++) {
int line = i;
if (interlace) {
if (iline >= ih) {
pass++;
switch (pass) {
case 2:
iline = 4;
break;
case 3:
iline = 2;
inc = 4;
break;
case 4:
iline = 1;
inc = 2;
break;
default:
break;
}
}
line = iline;
iline += inc;
}
line += iy;
if (line < height) {
int k = line * width;
int dx = k + ix; // start of line in dest
int dlim = dx + iw; // end of dest line
if ((k + width) < dlim) {
dlim = k + width; // past dest edge
}
int sx = i * iw; // start of line in source
while (dx < dlim) {
// map color and insert in destination
int index = ((int) pixels[sx++]) & 0xff;
int c = act[index];
if (c != 0) {
dest[dx] = c;
}
dx++;
}
}
}
image = new DixieMap(dest, width, height, Pixmap.Format.RGBA8888);
//Pixmap.createPixmap(dest, width, height, Config.ARGB_4444);
}
/**
* Gets the image contents of frame n.
*
* #return BufferedPixmap representation of frame, or null if n is invalid.
*/
public DixieMap getFrame(int n) {
if (frameCount <= 0)
return null;
n = n % frameCount;
return ((GifFrame) frames.elementAt(n)).image;
}
/**
* Reads GIF image from stream
*
* #param is
* containing GIF file.
* #return read status code (0 = no errors)
*/
public int read(InputStream is) {
init();
if (is != null) {
in = is;
readHeader();
if (!err()) {
readContents();
if (frameCount < 0) {
status = STATUS_FORMAT_ERROR;
}
}
} else {
status = STATUS_OPEN_ERROR;
}
try {
is.close();
} catch (Exception e) {
}
return status;
}
/**
* Decodes LZW image data into pixel array. Adapted from John Cristy's BitmapMagick.
*/
protected void decodeBitmapData() {
int nullCode = -1;
int npix = iw * ih;
int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi;
if ((pixels == null) || (pixels.length < npix)) {
pixels = new byte[npix]; // allocate new pixel array
}
if (prefix == null) {
prefix = new short[MAX_STACK_SIZE];
}
if (suffix == null) {
suffix = new byte[MAX_STACK_SIZE];
}
if (pixelStack == null) {
pixelStack = new byte[MAX_STACK_SIZE + 1];
}
// Initialize GIF data stream decoder.
data_size = read();
clear = 1 << data_size;
end_of_information = clear + 1;
available = clear + 2;
old_code = nullCode;
code_size = data_size + 1;
code_mask = (1 << code_size) - 1;
for (code = 0; code < clear; code++) {
prefix[code] = 0; // XXX ArrayIndexOutOfBoundsException
suffix[code] = (byte) code;
}
// Decode GIF pixel stream.
datum = bits = count = first = top = pi = bi = 0;
for (i = 0; i < npix;) {
if (top == 0) {
if (bits < code_size) {
// Load bytes until there are enough bits for a code.
if (count == 0) {
// Read a new data block.
count = readBlock();
if (count <= 0) {
break;
}
bi = 0;
}
datum += (((int) block[bi]) & 0xff) << bits;
bits += 8;
bi++;
count--;
continue;
}
// Get the next code.
code = datum & code_mask;
datum >>= code_size;
bits -= code_size;
// Interpret the code
if ((code > available) || (code == end_of_information)) {
break;
}
if (code == clear) {
// Reset decoder.
code_size = data_size + 1;
code_mask = (1 << code_size) - 1;
available = clear + 2;
old_code = nullCode;
continue;
}
if (old_code == nullCode) {
pixelStack[top++] = suffix[code];
old_code = code;
first = code;
continue;
}
in_code = code;
if (code == available) {
pixelStack[top++] = (byte) first;
code = old_code;
}
while (code > clear) {
pixelStack[top++] = suffix[code];
code = prefix[code];
}
first = ((int) suffix[code]) & 0xff;
// Add a new string to the string table,
if (available >= MAX_STACK_SIZE) {
break;
}
pixelStack[top++] = (byte) first;
prefix[available] = (short) old_code;
suffix[available] = (byte) first;
available++;
if (((available & code_mask) == 0) && (available < MAX_STACK_SIZE)) {
code_size++;
code_mask += available;
}
old_code = in_code;
}
// Pop a pixel off the pixel stack.
top--;
pixels[pi++] = pixelStack[top];
i++;
}
for (i = pi; i < npix; i++) {
pixels[i] = 0; // clear missing pixels
}
}
/**
* Returns true if an error was encountered during reading/decoding
*/
protected boolean err() {
return status != STATUS_OK;
}
/**
* Initializes or re-initializes reader
*/
protected void init() {
status = STATUS_OK;
frameCount = 0;
frames = new Vector<GifFrame>();
gct = null;
lct = null;
}
/**
* Reads a single byte from the input stream.
*/
protected int read() {
int curByte = 0;
try {
curByte = in.read();
} catch (Exception e) {
status = STATUS_FORMAT_ERROR;
}
return curByte;
}
/**
* Reads next variable length block from input.
*
* #return number of bytes stored in "buffer"
*/
protected int readBlock() {
blockSize = read();
int n = 0;
if (blockSize > 0) {
try {
int count = 0;
while (n < blockSize) {
count = in.read(block, n, blockSize - n);
if (count == -1) {
break;
}
n += count;
}
} catch (Exception e) {
e.printStackTrace();
}
if (n < blockSize) {
status = STATUS_FORMAT_ERROR;
}
}
return n;
}
/**
* Reads color table as 256 RGB integer values
*
* #param ncolors
* int number of colors to read
* #return int array containing 256 colors (packed ARGB with full alpha)
*/
protected int[] readColorTable(int ncolors) {
int nbytes = 3 * ncolors;
int[] tab = null;
byte[] c = new byte[nbytes];
int n = 0;
try {
n = in.read(c);
} catch (Exception e) {
e.printStackTrace();
}
if (n < nbytes) {
status = STATUS_FORMAT_ERROR;
} else {
tab = new int[256]; // max size to avoid bounds checks
int i = 0;
int j = 0;
while (i < ncolors) {
int r = ((int) c[j++]) & 0xff;
int g = ((int) c[j++]) & 0xff;
int b = ((int) c[j++]) & 0xff;
tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;
}
}
return tab;
}
/**
* Main file parser. Reads GIF content blocks.
*/
protected void readContents() {
// read GIF file content blocks
boolean done = false;
while (!(done || err())) {
int code = read();
switch (code) {
case 0x2C: // image separator
readBitmap();
break;
case 0x21: // extension
code = read();
switch (code) {
case 0xf9: // graphics control extension
readGraphicControlExt();
break;
case 0xff: // application extension
readBlock();
String app = "";
for (int i = 0; i < 11; i++) {
app += (char) block[i];
}
if (app.equals("NETSCAPE2.0")) {
readNetscapeExt();
} else {
skip(); // don't care
}
break;
case 0xfe:// comment extension
skip();
break;
case 0x01:// plain text extension
skip();
break;
default: // uninteresting extension
skip();
}
break;
case 0x3b: // terminator
done = true;
break;
case 0x00: // bad byte, but keep going and see what happens break;
default:
status = STATUS_FORMAT_ERROR;
}
}
}
/**
* Reads Graphics Control Extension values
*/
protected void readGraphicControlExt() {
read(); // block size
int packed = read(); // packed fields
dispose = (packed & 0x1c) >> 2; // disposal method
if (dispose == 0) {
dispose = 1; // elect to keep old image if discretionary
}
transparency = (packed & 1) != 0;
delay = readShort() * 10; // delay in milliseconds
transIndex = read(); // transparent color index
read(); // block terminator
}
/**
* Reads GIF file header information.
*/
protected void readHeader() {
String id = "";
for (int i = 0; i < 6; i++) {
id += (char) read();
}
if (!id.startsWith("GIF")) {
status = STATUS_FORMAT_ERROR;
return;
}
readLSD();
if (gctFlag && !err()) {
gct = readColorTable(gctSize);
bgColor = gct[bgIndex];
}
}
/**
* Reads next frame image
*/
protected void readBitmap() {
ix = readShort(); // (sub)image position & size
iy = readShort();
iw = readShort();
ih = readShort();
int packed = read();
lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlace
lctSize = (int) Math.pow(2, (packed & 0x07) + 1);
// 3 - sort flag
// 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color
// table size
interlace = (packed & 0x40) != 0;
if (lctFlag) {
lct = readColorTable(lctSize); // read table
act = lct; // make local table active
} else {
act = gct; // make global table active
if (bgIndex == transIndex) {
bgColor = 0;
}
}
int save = 0;
if (transparency) {
save = act[transIndex];
act[transIndex] = 0; // set transparent color if specified
}
if (act == null) {
status = STATUS_FORMAT_ERROR; // no color table defined
}
if (err()) {
return;
}
decodeBitmapData(); // decode pixel data
skip();
if (err()) {
return;
}
frameCount++;
// create new image to receive frame data
image = new DixieMap(width, height, Pixmap.Format.RGBA8888);
setPixels(); // transfer pixel data to image
frames.addElement(new GifFrame(image, delay)); // add image to frame
// list
if (transparency) {
act[transIndex] = save;
}
resetFrame();
}
/**
* Reads Logical Screen Descriptor
*/
protected void readLSD() {
// logical screen size
width = readShort();
height = readShort();
// packed fields
int packed = read();
gctFlag = (packed & 0x80) != 0; // 1 : global color table flag
// 2-4 : color resolution
// 5 : gct sort flag
gctSize = 2 << (packed & 7); // 6-8 : gct size
bgIndex = read(); // background color index
pixelAspect = read(); // pixel aspect ratio
}
/**
* Reads Netscape extenstion to obtain iteration count
*/
protected void readNetscapeExt() {
do {
readBlock();
if (block[0] == 1) {
// loop count sub-block
int b1 = ((int) block[1]) & 0xff;
int b2 = ((int) block[2]) & 0xff;
loopCount = (b2 << 8) | b1;
}
} while ((blockSize > 0) && !err());
}
/**
* Reads next 16-bit value, LSB first
*/
protected int readShort() {
// read 16-bit value, LSB first
return read() | (read() << 8);
}
/**
* Resets frame state for reading next image.
*/
protected void resetFrame() {
lastDispose = dispose;
lrx = ix;
lry = iy;
lrw = iw;
lrh = ih;
lastPixmap = image;
lastBgColor = bgColor;
dispose = 0;
transparency = false;
delay = 0;
lct = null;
}
/**
* Skips variable length blocks up to and including next zero length block.
*/
protected void skip() {
do {
readBlock();
} while ((blockSize > 0) && !err());
}
public Animation<TextureRegion> getAnimation(PlayMode playMode) {
int nrFrames = getFrameCount();
Pixmap frame = getFrame(0);
int width = frame.getWidth();
int height = frame.getHeight();
int vzones = (int)Math.sqrt((double)nrFrames);
int hzones = vzones;
while(vzones * hzones < nrFrames) vzones++;
int v, h;
Pixmap target = new Pixmap(width * hzones, height * vzones, Pixmap.Format.RGBA8888);
for(h = 0; h < hzones; h++) {
for(v = 0; v < vzones; v++) {
int frameID = v + h * vzones;
if(frameID < nrFrames) {
frame = getFrame(frameID);
target.drawPixmap(frame, h * width, v * height);
}
}
}
Texture texture = new Texture(target);
Array<TextureRegion> texReg = new Array<TextureRegion>();
for(h = 0; h < hzones; h++) {
for(v = 0; v < vzones; v++) {
int frameID = v + h * vzones;
if(frameID < nrFrames) {
TextureRegion tr = new TextureRegion(texture, h * width, v * height, width, height);
texReg.add(tr);
}
}
}
float frameDuration = (float)getDelay(0);
frameDuration /= 1000; // convert milliseconds into seconds
Animation<TextureRegion> result = new Animation<TextureRegion>(frameDuration, texReg, playMode);
return result;
}
public static Animation<TextureRegion> loadGIFAnimation(Animation.PlayMode playMode, InputStream is) {
GifDecoder gdec = new GifDecoder();
gdec.read(is);
return gdec.getAnimation(playMode);
}
}
please anyone help me
I could only make this work in the syncloader and not in the asyncloader is problably because it takes too much resources.
Too avoid the errors i made a GIF class to wrap the Animation this is also to dispose the texture when its no longer needed if this is not done it will create a memory leak.
public class GIF implements Disposable {
public Animation<TextureRegion> animation;
public Texture texture;
public GIF( Animation<TextureRegion> animation ) {
Object[] object = animation.getKeyFrames();
this.animation = animation;
this.texture = ((TextureRegion) object[ 0 ]).getTexture();
}
#Override
public void dispose() {
texture.dispose();
}
}
Here is the asset loader code:
public class Gifloader extends AsynchronousAssetLoader<GIF, Gifloader.GifloaderParameter> {
private Animation<TextureRegion> animation;
public Gifloader(FileHandleResolver resolver) {
super(resolver);
this.animation = null;
}
#Override
public void loadAsync(AssetManager manager, String fileName, FileHandle file, GifloaderParameter parameter) {
}
#Override
public GIF loadSync(AssetManager manager, String fileName, FileHandle file, GifloaderParameter parameter) {
PlayMode playMode = PlayMode.LOOP;
if ( parameter != null ){
playMode = parameter.playMode;
}
animation = (GifDecoder.loadGIFAnimation( playMode, file.read() ));
return new GIF( animation );
}
#SuppressWarnings( "rawtypes" )
#Override
public Array<AssetDescriptor> getDependencies(String fileName, FileHandle file, GifloaderParameter parameter) {
return null;
}
public static class GifloaderParameter extends AssetLoaderParameters<GIF> {
public PlayMode playMode = PlayMode.LOOP;
}
}

Getting X11 Window from PID - accessing array correctly? crashing

I'm converting these topis to jsctypes for X11:
How do I bring a processes window to the foreground on X Windows? (C++)
How to get an X11 Window from a Process ID?
It's working OK. I'm just running into one problem, when I loop the code its crashing.
For testing Im only looping once yet it still crashes:
The problem code is here:
searchForPidStartingAtWindow(wChildElementCasted, _disp, targetPid, true);
as soon as i run that code it crashes. even tho it returns on second iteration of this function 4argument is true
Full code, can copy and paste into Scratchpad (Borwser>Environment) and run.
Cu.import('resource://gre/modules/ctypes.jsm');
function doit() {
try {
_x11 = ctypes.open('libX11.so.6');
} catch (e) {
try {
var libName = ctypes.libraryName('X11');
} catch (e) {
_x11 = false;
console.error('Integration: Could not get libX11 name; not activating');
return;
}
try {
_x11 = ctypes.open(libName);
} catch (e) {
_x11 = false;
console.error('Integration: Could not open ' + libName + '; not activating');
return;
}
}
//start - type constants
X11Atom = ctypes.unsigned_long;
X11Bool = ctypes.int;
X11Display = new ctypes.StructType('Display');
X11Window = ctypes.unsigned_long;
X11Status = ctypes.int;
//end - type constants
//start - constants
var XA_CARDINAL = 6; //https://github.com/foudfou/FireTray/blob/d0c49867ea7cb815647bf13f2f1edb26439506ff/src/modules/ctypes/linux/x11.jsm#L117
var None = 0; //https://github.com/foudfou/FireTray/blob/d0c49867ea7cb815647bf13f2f1edb26439506ff/src/modules/ctypes/linux/x11.jsm#L63
var Success = 0;
//end - constants
/*
* typedef struct {
* int type;
* unsigned long serial; / * # of last request processed by server * /
* Bool send_event; / * true if this came from a SendEvent request * /
* Display *display; / * Display the event was read from * /
* Window window;
* Atom message_type;
* int format;
* union {
* char b[20];
* short s[10];
* long l[5];
* } data;
* } XClientMessageEvent;
*/
XClientMessageEvent = new ctypes.StructType('XClientMessageEvent', [
{'type': ctypes.int},
{'serial': ctypes.unsigned_long},
{'send_event': X11Bool},
{'display': X11Display.ptr},
{'window': X11Window},
{'message_type': X11Atom},
{'format': ctypes.int},
{'l0': ctypes.long},
{'l1': ctypes.long},
{'l2': ctypes.long},
{'l3': ctypes.long},
{'l4': ctypes.long}
]);
/*
* Status XFetchName(
* Display* display,
* Window w,
* char** window_name_return
* );
*/
XFetchName = _x11.declare('XFetchName', ctypes.default_abi, X11Status,
X11Display.ptr, X11Window, ctypes.char.ptr.ptr);
/*
* Status XQueryTree(
* Display* display,
* Window w,
* Window* root_return,
* Window* parent_return,
* Window** children_return,
* unsigned int* nchildren_return
* );
*/
XQueryTree = _x11.declare('XQueryTree', ctypes.default_abi, X11Status,
X11Display.ptr, X11Window, X11Window.ptr, X11Window.ptr, X11Window.ptr.ptr,
ctypes.unsigned_int.ptr);
/*
* int XFree(
* void* data
* );
*/
XFree = _x11.declare('XFree', ctypes.default_abi, ctypes.int, ctypes.voidptr_t);
/*
* Display *XOpenDisplay(
* _Xconst char* display_name
* );
*/
XOpenDisplay = _x11.declare('XOpenDisplay', ctypes.default_abi, X11Display.ptr,
ctypes.char.ptr);
/*
* int XCloseDisplay(
* Display* display
* );
*/
XCloseDisplay = _x11.declare('XCloseDisplay', ctypes.default_abi, ctypes.int,
X11Display.ptr);
/*
* int XFlush(
* Display* display
* );
*/
XFlush = _x11.declare('XFlush', ctypes.default_abi, ctypes.int, X11Display.ptr);
/*
* Window XDefaultRootWindow(
* Display* display
* );
*/
XDefaultRootWindow = _x11.declare('XDefaultRootWindow', ctypes.default_abi,
X11Window, X11Display.ptr);
/*
* Atom XInternAtom(
* Display* display,
* _Xconst char* atom_name,
* Bool only_if_exists
* );
*/
XInternAtom = _x11.declare('XInternAtom', ctypes.default_abi, X11Atom,
X11Display.ptr, ctypes.char.ptr, X11Bool);
/*
* Status XSendEvent(
* Display* display,
* Window w,
* Bool propagate,
* long event_mask,
* XEvent* event_send
* );
*/
XSendEvent = _x11.declare('XSendEvent', ctypes.default_abi, X11Status,
X11Display.ptr, X11Window, X11Bool, ctypes.long, XClientMessageEvent.ptr);
/*
* int XMapRaised(
* Display* display,
* Window w
* );
*/
XMapRaised = _x11.declare('XMapRaised', ctypes.default_abi, ctypes.int,
X11Display.ptr, X11Window);
/*
* extern int XGetWindowProperty(
* Display* display,
* Window w,
* Atom property,
* long long_offset,
* long long_length,
* Bool delete,
* Atom req_type,
* Atom* actual_type_return,
* int* actual_format_return,
* unsigned long* nitems_return,
* unsigned long* bytes_after_return,
* unsigned char** prop_return
* );
*/
XGetWindowProperty = _x11.declare('XGetWindowProperty', ctypes.default_abi,
ctypes.int, X11Display.ptr, X11Window, X11Atom, ctypes.long, ctypes.long,
X11Bool, X11Atom, X11Atom.ptr, ctypes.int.ptr, ctypes.unsigned_long.ptr,
ctypes.unsigned_long.ptr, ctypes.char.ptr.ptr);
////////////////////////
////END DECLARATIONS
////////////////////////
var _x11Display = XOpenDisplay(null);
if (!_x11Display) {
console.error('Integration: Could not open display; not activating');
_x11 = false;
return;
}
var _x11RootWindow = XDefaultRootWindow(_x11Display);
if (!_x11RootWindow) {
console.error('Integration: Could not get root window; not activating');
_x11 = false;
return;
}
//start - WindowsMatchingPid from https://stackoverflow.com/questions/151407/how-to-get-an-x11-window-from-a-process-id
//start - searchForPidStartingAtWindow func
var _atomPIDInited = false;
var _atomPID;
var _matchingWins = [];
function searchForPidStartingAtWindow(w, _disp, targetPid, isRecurse) { // when you call must always leave isRecurse null or false, its only used by the function to identify when to clear out _matchingWins
if (!isRecurse) {
//user just called this function so clear _matchingWins
_matchingWins = [];
} else {
console.log('isRecurse so return');
}
console.log('h1');
//make sure to clear _matchingWins arr before running this
if (!_atomPIDInited) {
_atomPID = XInternAtom(_disp, '_NET_WM_PID', true);
console.log('_atomPID:', _atomPID, _atomPID.toString(), parseInt(_atomPID));
if(_atomPID == None) {
throw new Error('No such atom ("_NET_WM_PID"), _atomPID:', _atomPID);
}
_atomPIDInited = true;
}
var returnType = new X11Atom(),
returnFormat = new ctypes.int(),
nItemsReturned = new ctypes.unsigned_long(),
nBytesAfterReturn = new ctypes.unsigned_long(),
propData = new ctypes.char.ptr();
console.log('h2');
console.log('_disp:', _disp, 'w:', w, '_atomPID:', _atomPID);
var rez = XGetWindowProperty(_disp, w, _atomPID, 0, 1024, false, XA_CARDINAL, returnType.address(), returnFormat.address(), nItemsReturned.address(), nBytesAfterReturn.address(), propData.address());
console.log('h3');
console.log('XGetWindowProperty', 'rez:', rez, 'returnType:', returnType, 'nItemsReturned:', nItemsReturned, 'nBytesAfterReturn:', nBytesAfterReturn, 'propData:', propData);
console.log('propData:', ctypes.cast(propData, ctypes.unsigned_int).value);
if (rez == Success) {
var nElements = ctypes.cast(nItemsReturned, ctypes.unsigned_int).value;
if(nElements) {
var rezArr = [propData, nElements];
console.log('rezArr:', rezArr);
} else {
console.log('no elements for rezArr, nElements:', nElements);
}
var nPid = ctypes.cast(propData, ctypes.unsigned_int).value;
if (nPid != 0) {
_matchingWins.push(w);
console.log('h4');
var rez = XFree(propData);
console.log('rez of XFree on propData:', rez);
} else {
console.log('no pid on this window');
}
} else {
console.error('failed on XGetWindowProperty, rez:', rez);
}
if (isRecurse) {
return;
}
console.log('recurse into');
// recurse into child windows
var wRoot = new X11Window();
var wParent = new X11Window();
var wChild = new X11Window.ptr();
var nChildren = new ctypes.unsigned_int();
var rez = XQueryTree(_disp, w, wRoot.address(), wParent.address(), wChild.address(), nChildren.address());
if(rez != 0) { //can probably test this against `None` instead of `0`
var nChildrenCasted = ctypes.cast(nChildren, ctypes.unsigned_int).value;
var wChildCasted = ctypes.cast(wChild, ctypes.ArrayType(X11Window, nChildrenCasted).ptr).contents; //console.log('wChildCasted:', wChildCasted);
//var wChildElementCasted = ctypes.cast(wChildCasted.addressOfElement(0), X11Window).value;
//console.log('wChildElementCasted:', wChildElementCasted, 'w:', w);
//for(var i=0; i<wChildCasted.length; i++) {
for(var i=0; i<1; i++) {
var wChildElementCasted = ctypes.cast(wChildCasted.addressOfElement(i), X11Window).value;
console.log('wChildElementCasted:', wChildElementCasted, 'w:', w);
searchForPidStartingAtWindow(wChildElementCasted, _disp, targetPid, true);
}
} else {
console.warn('this window has no children, rez:', rez);
}
return _matchingWins;
}
//end - searchForPidStartingAtWindow func
var wins = searchForPidStartingAtWindow(_x11RootWindow, _x11Display, 12312132); //dont pass isRecurse here, important, otherwise if use this func multiple times, you'll have left over windows in the returned array from a previous run of this func
console.log('wins:', wins);
//end - WindowsMatchingPid
XCloseDisplay(_x11Display);
//_X11BringToForeground(win, intervalID);
}
doit();
Solved it, I had to use this code:
var wChildCasted = ctypes.cast(wChild, X11Window.array(nChildrenCasted).ptr).contents; //SAME AS: `var wChildCasted = ctypes.cast(wChild, ctypes.ArrayType(X11Window, nChildrenCasted).ptr).contents;`
for(var i=0; i<wChildCasted.length; i++) {
var wChildElementCasted = wChildCasted.addressOfElement(i).contents; //DO NOT DO `var wChildElementCasted = ctypes.cast(wChildCasted.addressOfElement(i), X11Window).value;`, it crashes on line 234 when passing as `w` into `XGetWindowProperty`
//console.log('wChildElementCasted:', wChildElementCasted, 'w:', w);
searchForPidStartingAtWindow(wChildElementCasted, _disp, targetPid, true);
}
notice how the wChildElementCasted is not longer casted, I simply read the .contents. this is the right way to do it for sure.
copy paste and fully working here: https://gist.github.com/Noitidart/5a24e8a4f8886ce7bbf6

Save image with Processing

I'm trying to save an image after certain time, the problem is that the image size is bigger than the display so when I use the save or saveFrame function it only saves the image that I can see in the display. There is any other way to save the whole image?
This is my code:
PImage picture, pictureFilter, img;
int total, cont, current;
ArrayList<ArrayList<Position>> columns;
String[] fontList;
public class Position {
public int x;
public int y;
}
void setup() {
fontList = PFont.list();
picture = loadImage("DSC05920b.JPG");
pictureFilter = loadImage("filtrePort2.jpg");
frame.setResizable(true);
size(picture.width, picture.height);
columns = new ArrayList<ArrayList<Position>>();
for(int i = 0; i < picture.width; i++) {
ArrayList<Position> row = new ArrayList<Position>();
for(int j = 0; j < picture.height; j++){
Position p = new Position();
p.x = i;
p.y = j;
row.add(p);
}
columns.add(row);
}
total = picture.width * picture.height;
cont = total;
current = 0;
img = createImage(picture.width, picture.height, RGB);
}
float randomLetter() {
float value = 23;
boolean found = false;
while(!found) {
value = random(48, 122);
if(value >48 && value <58) found = true;
if(value >65 && value <91) found = true;
if(value >97 && value <123) found = true;
}
return value;
}
void draw() {
int x = int(random(0, columns.size()));
ArrayList<Position> rows = columns.get(x);
int y = int(random(0, rows.size()));
Position p = rows.get(y);
color c = pictureFilter.get(p.x, p.y);
int r = (c >> 16) & 0xFF; // Faster way of getting red(argb)
if(r < 240) {
PFont f = createFont(fontList[int(random(0,fontList.length))],random(5, 24),true);
textFont(f);
fill(picture.get(p.x,p.y));
char letter = (char) int(randomLetter());
text(letter, p.x, p.y);
}
if(rows.size() == 1) {
if(columns.size() == 1) {
saveFrame("lol.jpg");
columns.remove(x);
} else {
columns.remove(x);
}
} else {
println(rows.size());
rows.remove(y);
}
--cont;
float percent = float(total-cont)/float(total)*100;
if(int(percent) != current) {
current = int(percent);
save("image_" + current + ".jpg");
}
println("DONE: " + (total-cont) + "/" + total + " Progress: " + percent + "%");
}
The code do a lot of stuff but the part that its not working well is at the final when I check if the percentage have been increased in order to save the image
You can write this into a PGraphics context - aka a graphics buffer.
The buffer can be as big as you need it to be, and you can choose whether to draw it on the screen or not..
// Create the buffer at the size you need, and choose the renderer
PGraphics pg = createGraphics(myImage.width, myImage.height, P2D);
// Wrap all your drawing functions in the pg context - e.g.
PFont f = createFont(fontList[int(random(0,fontList.length))],random(5, 24),true);
textFont(f);
pg.beginDraw();
pg.fill(picture.get(p.x,p.y));
char letter = (char) int(randomLetter());
pg.text(letter, p.x, p.y);
pg.endDraw();
// Draw your PG to the screen and resize the representation of it to the screen bounds
image(pg, 0, 0, width, height); // <-- this wont actually clip/resize the image
// Save it
pg.save("image_" + current + ".jpg");
The PImage class contains a save() function that exports to file. The API should be your first stop for questions like this.

How to convert pixel data to grayscale image in java?

I 've gray pixels but don't know to create gray scale image
Create grayscale image on the fly in Java (from http://technojeeves.com/joomla/index.php/free/89-create-grayscale-image-on-the-fly-in-java)
import java.awt.*;
import java.awt.color.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.ImageIO;
public class BMP {
/**
* (Testing only)
*/
public static void main(String[] args) throws Exception {
BMP.makeMeCross(args[0]);
}
/**
*
* #param filename The file name for the 'crosshair' image
*
* #throws IOException If the file could not be written to by ImageIO
*/
public static void makeMeCross(String filename) throws IOException {
int sz = 101;
byte[] buffer = new byte[sz * sz];
for (int i = 0; i < sz; i++) {
for (int j = 0; j < sz; j++) {
// Make a 'crosshair' pattern
buffer[(i * sz) + j] = ((j == 50) || (i == 50)) ? (byte) 255 : 0;
}
}
ImageIO.write(BMP.getGrayscale(101, buffer), "PNG", new File(filename));
}
/**
*
* #param width The image width (height derived from buffer length)
* #param buffer The buffer containing raw grayscale pixel data
*
* #return THe grayscale image
*/
public static BufferedImage getGrayscale(int width, byte[] buffer) {
int height = buffer.length / width;
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
int[] nBits = { 8 };
ColorModel cm = new ComponentColorModel(cs, nBits, false, true,
Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
SampleModel sm = cm.createCompatibleSampleModel(width, height);
DataBufferByte db = new DataBufferByte(buffer, width * height);
WritableRaster raster = Raster.createWritableRaster(sm, db, null);
BufferedImage result = new BufferedImage(cm, raster, false, null);
return result;
}
}
There is a javax.swing.GrayFilter worth to look at for this purpose. It can be used like this:
Icon icon = myLabel.getIcon();
Image img = gc.createCompatibleImage(icon.getIconWidth(), icon.getIconHeight(), Transparency.TRANSLUCENT);
icon.paintIcon(this, img.getGraphics(), 0, 0);
img = GrayFilter.createDisabledImage(img);
myLabel.setIcon(new ImageIcon(img));

Resources