Uploading multipart file from android to WCF - java

I am trying to upload .JPG file from android to WCF webservice.
To upload the file from Android i tried 2 ways:
1- Retrofit:
#Multipart
#POST("/UploadFile/{fileName}")
void UploadFile(#Path("fileName") String fileName, #Part("image") TypedFile image, Callback<String> callBack);
2- Android Asynchronous Http Client
here there was 2 options for uploading it:
a- Adding InputStream to the RequestParams:
RequestParams params = new RequestParams();
try {
InputStream stream = new FileInputStream(fileImage);
params.put("image", stream, fileImage.getName() );
client.post(Constants.SERVICE_URL + "/UploadFile/" + fileImage.getName()
, params, getResponseHandler());
} catch (Exception e) {
Utils.LogError("ERROR: " + e.getLocalizedMessage());
}
b- Ading File object to the RequestParams:
RequestParams params = new RequestParams();
try {
//InputStream stream = new FileInputStream(fileImage);
params.put("image", fileImage);
client.post(Constants.SERVICE_URL + "/UploadFile/" + fileImage.getName()
, params, getResponseHandler());
} catch (Exception e) {
Utils.LogError("ERROR: " + e.getLocalizedMessage());
}
All those, sent successfully to server, The received file before parsing looks something like this:
--b1b13fd2-4212-45bb-bb5c-fd4dc074fd1b
Content-Disposition: form-data; name="image"; filename="71d9d7fc-cfa8-40b6-b7aa-5c287cf31c72.jpg"
Content-Type: image/jpeg
Content-Length: 2906
Content-Transfer-Encoding: binary
���� JFIF �� C .................very long string of this stuff
Þq�Ã�9�A?� �0pi1�zq�<�#��:��PV���]|�e�K�mv �ǜ.1�q���&��8��u�m�?�ӵ/���0=8�x�:t�8��>�ׁ���1�POM�k����eea1��ǧq�}8�6��q� � �� .;p1K�g�Onz�Q�oås�a�׌p1�?>3#���z��0=��m$�H ǧ��Ӄ�v?��x��<q��.8܃��� ��2}1�� c���ϧ q�oA�Rt>��t�=�?����2y�q�큊A����:��q�#���_�~�Q�w��Pu��Ƿ�q�#q��{cۦ���}0:b�|�=#��9�BEV���?O��װ�g���׎z<N� ��� v�=�?������=�<}x�#'�d�8��׌e����,�\�4wVV���f�pB���㢁�L{��%$�v裶G8x��b�?���� �]�=:�ӕ����
--b1b13fd2-4212-45bb-bb5c-fd4dc074fd1b--
So I used mulipart parser in order to take out the bytes of the file, the write them to file on the server to finish the uploading.
Here is the code of the multipartparser i used:
public class MultipartParser
{
public MultipartParser(string contents)
{
this.Parse(contents);
}
private void Parse(string contents)
{
Encoding encoding = Encoding.UTF8;
this.Success = false;
// Read the stream into a byte array
byte[] data = encoding.GetBytes(contents);
// Copy to a string for header parsing
string content = contents;
// The first line should contain the delimiter
int delimiterEndIndex = content.IndexOf("\r\n");
if (delimiterEndIndex > -1)
{
string delimiter = content.Substring(0, content.IndexOf("\r\n"));
// Look for Content-Type
Regex re = new Regex(#"(?<=Content\-Type:)(.*?)(?=\r\n)");
Match contentTypeMatch = re.Match(content);
// Look for filename
re = new Regex(#"(?<=filename\=\"")(.*?)(?=\"")");
Match filenameMatch = re.Match(content);
#region added
re = new Regex(#"(?<=Content\-Transfer\-Encoding:)(.*?)(?=\r\n\r\n)");
Match contentTransferEncodingMatch = re.Match(content);
#endregion
// Did we find the required values?
if (contentTypeMatch.Success && filenameMatch.Success && contentTransferEncodingMatch.Success)
{
// Set properties
this.ContentType = contentTypeMatch.Value.Trim();
this.Filename = filenameMatch.Value.Trim();
this.ContentEncoding = contentTransferEncodingMatch.Value.Trim();
// Get the start & end indexes of the file contents
//int startIndex = contentTypeMatch.Index + contentTypeMatch.Length + "\r\n\r\n".Length;
int startIndex = contentTransferEncodingMatch.Index + contentTransferEncodingMatch.Length + "\r\n\r\n".Length;
byte[] delimiterBytes = encoding.GetBytes("\r\n" + delimiter);
string finalDelimeterStr = "\r\n"+delimiter + "--";
byte[] endDilimeterBytes = encoding.GetBytes(finalDelimeterStr);
//byte[] fileBytes = Array.Copy()
//int endIndex = IndexOf(data, endDilimeterBytes, startIndex);
int endIndex = SimpleBoyerMooreSearch(data, endDilimeterBytes);
int contentLength = endIndex - startIndex;
// Extract the file contents from the byte array
byte[] fileData = new byte[contentLength];
Buffer.BlockCopy(data, startIndex, fileData, 0, contentLength);
this.FileContents = fileData;
this.Success = true;
}
}
}
public int SimpleBoyerMooreSearch(byte[] haystack, byte[] needle)
{
int[] lookup = new int[256];
for (int i = 0; i < lookup.Length; i++) { lookup[i] = needle.Length; }
for (int i = 0; i < needle.Length; i++)
{
lookup[needle[i]] = needle.Length - i - 1;
}
int index = needle.Length - 1;
byte lastByte = needle.Last();
while (index < haystack.Length)
{
var checkByte = haystack[index];
if (haystack[index] == lastByte)
{
bool found = true;
for (int j = needle.Length - 2; j >= 0; j--)
{
if (haystack[index - needle.Length + j + 1] != needle[j])
{
found = false;
break;
}
}
if (found)
return index - needle.Length + 1;
else
index++;
}
else
{
index += lookup[checkByte];
}
}
return -1;
}
public static byte[] ToByteArray(Stream stream)
{
byte[] buffer = new byte[32768];
using (MemoryStream ms = new MemoryStream())
{
while (true)
{
int read = stream.Read(buffer, 0, buffer.Length);
if (read <= 0)
return ms.ToArray();
ms.Write(buffer, 0, read);
}
}
}
public bool Success
{
get;
private set;
}
public string ContentType
{
get;
private set;
}
public string ContentEncoding
{
get;
private set;
}
public string Filename
{
get;
private set;
}
public byte[] FileContents
{
get;
private set;
}
}
The parser is taking out the bytes, and parse the received multipart file.
The result file is not showing and it shows error reading file or something.
What i noticed after comparing the files it that the original and received file are different, here is the comparison in Notepad++:
some letters are exists in the original and not exists in the received!
here is the WCF Function declaration and code:
IService.cs:
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/UploadFile/{fileName}"
, ResponseFormat = WebMessageFormat.Json)]
string UploadFile(string fileName ,Stream image);
Service.cs:
public string UploadFile(string fileName, Stream image)
{
string dirPath = System.Web.Hosting.HostingEnvironment.MapPath("~/Logs/");
//string path = dirPath+"log.txt";
// Read the stream into a byte array
byte[] data = MultipartParser.ToByteArray(image);
// Copy to a string
string content = Encoding.UTF8.GetString(data);
File.WriteAllText(dirPath + fileName + ".txt", content); // for checking the result file
MultipartParser parser = new MultipartParser(content);
if (parser != null )
{
if (parser.Success)
{
if (parser.FileContents == null)
return "fail: Null Content";
byte[] bitmap = parser.FileContents;
File.WriteAllBytes(dirPath + fileName +"contents",bitmap);
try
{
using (Image outImage = Image.FromStream(new MemoryStream(bitmap)))
{
outImage.Save(fileName, ImageFormat.Jpeg);
}
return "success";
}
catch (Exception e)
{ // I get this exception all the time
return "Fail: e " + e.Message;
}
}
return "fail not success";
}
return "fail";
}
I tried every possible solution came to my mind, still could not get whats wrong!!! is the problem in the encoding while sending or the parser!??
Please what can be the problem!? i am struggling with this for 3 days!
Thank you ALL :)

The were 2 problems:
The parser
Decoding the bytes to string was not good idea.
I modified the parser to this one and it will take care of the rest:
public class MultipartParser
{
public MultipartParser(Stream stream)
{
this.Parse(stream);
}
private void Parse(Stream stream)
{
this.Success = false;
if(!stream.CanRead)
return;
// Read the stream into a byte array
byte[] data = MultipartParser.ToByteArray(stream);
if (data.Length < 1)
return;
// finding the delimiter (the string in the beginning and end of the file
int delimeterIndex = MultipartParser.SimpleBoyerMooreSearch(data, Encoding.UTF8.GetBytes("\r\n")); // here we got delimeter index
if (delimeterIndex == -1) return;
byte[] delimeterBytes = new byte[delimeterIndex];
Array.Copy(data, delimeterBytes, delimeterIndex);
// removing the very first couple of lines, till we get the beginning of the JPG file
byte[] newLineBytes = Encoding.UTF8.GetBytes("\r\n\r\n");
int startIndex = 0;
startIndex = MultipartParser.SimpleBoyerMooreSearch(data, newLineBytes);
if (startIndex == -1)
return;
int startIndexWith2Lines = startIndex + 4; // 4 is the bytes of "\r\n\r\n"
int newLength = data.Length - startIndexWith2Lines;
byte[] newByteArray = new byte[newLength];
Array.Copy(data, startIndex + 4, newByteArray, 0, newLength - 1);
// check for the end of the stream, is ther same delimeter
int isThereDelimeterInTheEnd = MultipartParser.SimpleBoyerMooreSearch(newByteArray, delimeterBytes);
if (isThereDelimeterInTheEnd == -1) return; // the file corrupted so
int endIndex = isThereDelimeterInTheEnd - delimeterBytes.Length;
byte[] lastArray = new byte[endIndex];
Array.Copy(newByteArray, 0, lastArray, 0, endIndex);
this.FileContents = lastArray;
this.Success = true;
}
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
static string GetString(byte[] bytes)
{
char[] chars = new char[bytes.Length / sizeof(char)];
System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
public static int SimpleBoyerMooreSearch(byte[] haystack, byte[] needle)
{
int[] lookup = new int[256];
for (int i = 0; i < lookup.Length; i++) { lookup[i] = needle.Length; }
for (int i = 0; i < needle.Length; i++)
{
lookup[needle[i]] = needle.Length - i - 1;
}
int index = needle.Length - 1;
byte lastByte = needle.Last();
while (index < haystack.Length)
{
var checkByte = haystack[index];
if (haystack[index] == lastByte)
{
bool found = true;
for (int j = needle.Length - 2; j >= 0; j--)
{
if (haystack[index - needle.Length + j + 1] != needle[j])
{
found = false;
break;
}
}
if (found)
return index - needle.Length + 1;
else
index++;
}
else
{
index += lookup[checkByte];
}
}
return -1;
}
private int IndexOf(byte[] searchWithin, byte[] serachFor, int startIndex)
{
int index = 0;
int startPos = Array.IndexOf(searchWithin, serachFor[0], startIndex);
if (startPos != -1)
{
while ((startPos + index) < searchWithin.Length)
{
if (searchWithin[startPos + index] == serachFor[index])
{
index++;
if (index == serachFor.Length)
{
return startPos;
}
}
else
{
startPos = Array.IndexOf<byte>(searchWithin, serachFor[0], startPos + index);
if (startPos == -1)
{
return -1;
}
index = 0;
}
}
}
return -1;
}
public static byte[] ToByteArray(Stream stream)
{
byte[] buffer = new byte[32768];
using (MemoryStream ms = new MemoryStream())
{
while (true)
{
int read = stream.Read(buffer, 0, buffer.Length);
if (read <= 0)
return ms.ToArray();
ms.Write(buffer, 0, read);
}
}
}
public bool Success
{
get;
private set;
}
public byte[] FileContents
{
get;
private set;
}
}
So you can use this parser for this kind of multipart files encoding:
--b1b13fd2-4212-45bb-bb5c-fd4dc074fd1b
Content-Disposition: form-data; name="image"; filename="71d9d7fc-cfa8-40b6-b7aa-5c287cf31c72.jpg"
Content-Type: image/jpeg
Content-Length: 2906
Content-Transfer-Encoding: binary
���� JFIF �� C .................very long string of this stuff
Þq�Ã�9�A?� �0pi1�zq�<�#��:��PV���]|�e�K�mv �ǜ.1�q���&��8��u�m�?�ӵ/��Ƿ�q�#q��{cۦ���}0:b�|�=#��9�BEV���?O��װ�g���׎z<N� ��� v�=�?������=�<}x�#'�d�8��׌e����,�\�4wVV���f�pB���㢁�L{��%$�v裶G8x��b�?���� �]�=:�ӕ����
--b1b13fd2-4212-45bb-bb5c-fd4dc074fd1b--
Hope it helps somebody else.

You could try to encode the jpeg to base64 before sending it. As far as I know, this is a proper solution. Decoding it on the server, should be no problem. (Sry, I wanted to write a comment - but I'm not allowed to it)

Related

Java 8: How to chunk multipart file for POST request

I have a multipart file, it will be an image or video, which needs to be chunked for POST request. How can I chunk the file into byte array segments?
edit: I'm using Twitter API to upload image, according to their docs, media must be chunked
I've found a solution thanks to https://www.baeldung.com/2013/04/04/multipart-upload-on-s3-with-jclouds/
public final class MediaUtil {
public static int getMaximumNumberOfParts(byte[] byteArray) {
int numberOfParts = byteArray.length / (1024 * 1024); // 1MB
if (numberOfParts == 0) {
return 1;
}
return numberOfParts;
}
public static List<byte[]> breakByteArrayIntoParts(byte[] byteArray, int maxNumberOfParts) {
List<byte[]> parts = new ArrayList<>();
int fullSize = byteArray.length;
long dimensionOfPart = fullSize / maxNumberOfParts;
for (int i = 0; i < maxNumberOfParts; i++) {
int previousSplitPoint = (int) (dimensionOfPart * i);
int splitPoint = (int) (dimensionOfPart * (i + 1));
if (i == (maxNumberOfParts - 1)) {
splitPoint = fullSize;
}
byte[] partBytes = Arrays.copyOfRange(byteArray, previousSplitPoint, splitPoint);
parts.add(partBytes);
}
return parts;
}
}
// Post the request
int maxParts = MediaUtil.getMaximumNumberOfParts(multipartFile.getBytes());
List<byte[]> bytes = MediaUtil.breakByteArrayIntoParts(multipartFile.getBytes(), maxParts);
int segment = 0;
for (byte[] b : bytes) {
// POST request here
segment++;
}
Well, you may need this:
File resource = ResourceUtils.getFile(path);
if (resource.isFile()) {
byte[] bytes = readFile2Bytes(new FileInputStream(resource));
}
private byte[] readFile2Bytes(FileInputStream fis) throws IOException {
int length = 0;
byte[] buffer = new byte[size];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((length = fis.read(buffer)) != -1) {
baos.write(buffer, 0, length);
}
return baos.toByteArray();
}

How to use XOR to develop a ​OTPInputStream​ in Java

I want to develop a ​OTPInputStream ​in Java that extends the ​InputStream ​and takes another input stream of key data and provides a stream encrypting / decrypting input stream.I need to develop a test program to show the use of ​OTPInputStream​ that uses XOR and arbitrary data.
I tried with this code but I have problem that is
java.io.FileInputStream cannot be cast to java.lang.CharSequence
What should I do here?
public class Bitwise_Encryption {
static String file = "" ;
static String key = "VFGHTrbg";
private static int[] encrypt(FileInputStream file, String key) {
int[] output = new int[((CharSequence) file).length()];
for(int i = 0; i < ((CharSequence) file).length(); i++) {
int o = (Integer.valueOf(((CharSequence) file).charAt(i)) ^ Integer.valueOf(key.charAt(i % (key.length() - 1)))) + '0';
output[i] = o;
}
return output;
}
private static String decrypt(int[] input, String key) {
String output = "";
for(int i = 0; i < input.length; i++) {
output += (char) ((input[i] - 48) ^ (int) key.charAt(i % (key.length() - 1)));
}
return output;
}
public static void main(String args[]) throws FileNotFoundException {
FileInputStream file = new FileInputStream("directory");
encrypt(file,key);
//decrypt();
int[] encrypted = encrypt(file,key);
System.out.println("Encrypted Data is :");
for(int i = 0; i < encrypted.length; i++)
System.out.printf("%d,", encrypted[i]);
System.out.println("");
System.out.println("---------------------------------------------------");
System.out.println("Decrypted Data is :");
System.out.println(decrypt(encrypted,key));
}
}
Think what you want is just file.read() and file.getChannel().size() to read one character at a time and get the size of the file
Try something like this:
private static int[] encrypt(FileInputStream file, String key) {
int fileSize = file.getChannel().size();
int[] output = new int[fileSize];
for(int i = 0; i < output.length; i++) {
char char1 = (char) file.read();
int o = (char1 ^ Integer.valueOf(key.charAt(i % (key.length() - 1)))) + '0';
output[i] = o;
}
return output;
}
Will have to do some error handling because file.read() will return -1 if the end of the file has been reached and as pointed out reading one byte at a time is lot of IO operations and can slow down performance. You can keep the data in a buffer and read it another way like this:
private static int[] encrypt(FileInputStream file, String key) {
int fileSize = file.getChannel().size();
int[] output = new int[fileSize];
int read = 0;
int offset = 0;
byte[] buffer = new byte[1024];
while((read = file.read(buffer)) > 0) {
for(int i = 0; i < read; i++) {
char char1 = (char) buffer[i];
int o = (char1 ^ Integer.valueOf(key.charAt(i % (key.length() - 1)))) + '0';
output[i + offset] = o;
}
offset += read;
}
return output;
}
This will read in 1024 bytes at a time from the file and store it in your buffer, then you can loop through the buffer to do your logic. The offset value is to store where in our output the current spot is. Also you will have to make sure that i + offset doesn't exceed your array size.
UPDATE
After working with it; i decided to switch to Base64 Encoding/Decoding to remove non-printable characters:
private static String encrypt(InputStream file, String key) throws Exception {
int read = 0;
byte[] buffer = new byte[1024];
try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
while((read = file.read(buffer)) > 0) {
baos.write(buffer, 0, read);
}
return base64Encode(xorWithKey(baos.toByteArray(), key.getBytes()));
}
}
private static String decrypt(String input, String key) {
byte[] decoded = base64Decode(input);
return new String(xorWithKey(decoded, key.getBytes()));
}
private static byte[] xorWithKey(byte[] a, byte[] key) {
byte[] out = new byte[a.length];
for (int i = 0; i < a.length; i++) {
out[i] = (byte) (a[i] ^ key[i%key.length]);
}
return out;
}
private static byte[] base64Decode(String s) {
return Base64.getDecoder().decode(s.trim());
}
private static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
This method is cleaner and doesn't require knowing the size of your InputStream or do any character conversions. It reads your InputStream into an OutputStream to do the Base64 Encoding as well to remove non printable characters.
I have tested this and it works both for encrypting and decrypting.
I got the idea from this answer:
XOR operation with two strings in java

how to get the original size of the image in java

I have tried to get the size of the image by .length in java.
However the original size of the image is several bytes higher than that.
What is the reason for this? Is there any code to get the original size?
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import javax.imageio.ImageIO;
public class Array {
public static void main(String argv[]) throws IOException {
String imageFile1 = "C:/Users/Desktop/4.jpg";
File file = new File(imageFile1);
BufferedImage originalImage = ImageIO.read(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(originalImage, "jpg", baos);
byte[] imageInByte = baos.toByteArray();
System.out.println("The length in bytes " + imageInByte.length);
}
}
I think it's about jpeg file header size.
If you want to get an original size when copying image file.
You can use just file copy rather then image file copy.
Or, you can make your own jpeg library, if you really want.
For just one example,
this is one of the old-style code by using java's NIO.
private static void fileCopy(String from, String to) {
FileChannel fromCh = null;
FileChannel toCh = null;
FileInputStream fin = null;
FileOutputStream fout = null;
try {
fin = new FileInputStream(new File(from));
fromCh = fin.getChannel();
fout = new FileOutputStream(new File(to));
toCh = fout.getChannel();
fromCh.transferTo(0, fin.available(), toCh);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fin != null)
try {
fin.close();
} catch (IOException e) {
}
if (fout != null)
try {
fout.close();
} catch (IOException e) {
}
}
}
You can get a file from the original file with the same size.
Check the reference site below:
https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format
I tested it the difference between two file, one is the original another is the copy one. I got an jpeg image from googling.
I modified some code form here in order to analyze the jpeg header file .
Here is the method:
final public static ImageProperties getJpegProperties(File file) throws FileNotFoundException, IOException {
BufferedInputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(file));
// check for "magic" header
byte[] buf = new byte[2];
int count = in.read(buf, 0, 2);
if (count < 2) {
throw new RuntimeException("Not a valid Jpeg file!");
}
if ((buf[0]) != (byte) 0xFF || (buf[1]) != (byte) 0xD8) {
throw new RuntimeException("Not a valid Jpeg file!");
}
int width = 0;
int height = 0;
char[] comment = null;
boolean hasDims = false;
boolean hasComment = false;
int ch = 0;
int totalHeaderLen = 0;
while (ch != 0xDA && !(hasDims && hasComment)) {
/* Find next marker (JPEG markers begin with 0xFF) */
while (ch != 0xFF) {
ch = in.read();
}
/* JPEG markers can be padded with unlimited 0xFF's */
while (ch == 0xFF) {
ch = in.read();
}
/* Now, ch contains the value of the marker. */
int length = 256 * in.read();
length += in.read();
totalHeaderLen += length;
if (length < 2) {
throw new RuntimeException("Not a valid Jpeg file!");
}
/* Now, length contains the length of the marker. */
if (ch >= 0xC0 && ch <= 0xC3) {
in.read();
height = 256 * in.read();
height += in.read();
width = 256 * in.read();
width += in.read();
for (int foo = 0; foo < length - 2 - 5; foo++) {
in.read();
}
hasDims = true;
} else if (ch == 0xFE) {
// that's the comment marker
comment = new char[length - 2];
for (int foo = 0; foo < length - 2; foo++)
comment[foo] = (char) in.read();
hasComment = true;
} else {
// just skip marker
for (int foo = 0; foo < length - 2; foo++) {
in.read();
}
}
}
if(comment == null) comment = "no comment".toCharArray();
return (new ImageProperties(width, height, new String(comment), totalHeaderLen, "jpeg"));
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
}
}
The main method is :
public static void main(String argv[]) throws IOException {
String imageFile1 = "resource/4.jpg";
String imageFile2 = "resource/4_jpg.jpg";
//copyImage(imageFile1);
ImageProperties origin = getJpegProperties(new File(imageFile1));
ImageProperties copyed = getJpegProperties(new File(imageFile2));
System.out.println("============ Original one ===========");
System.out.println("comments(origin) : " + origin.getComments());
System.out.println("Height(origin) : " + origin.getHeight());
System.out.println("Width(origin) : " + origin.getWidth());
System.out.println("Header Length(origin) : " + origin.getHeaderLen());
//System.out.println("suffix(origin) : " + origin.getSuffix());
System.out.println();
System.out.println("============ Copy one ===========");
System.out.println("comments(copy) : " + copyed.getComments());
System.out.println("Height(copy) : " + copyed.getHeight());
System.out.println("Width(copy) : " + copyed.getWidth());
System.out.println("Header Length(copy) : " + copyed.getHeaderLen());
//System.out.println("suffix(copy) : " + copyed.getSuffix());
}
I copy the original image first using copyImage method here.
static BufferedImage copyImage(BufferedImage source) {
BufferedImage b = new BufferedImage(source.getWidth(), source.getHeight(), source.getType());
Graphics g = b.getGraphics();
g.drawImage(source, 0, 0, null);
g.dispose();
return b;
}
I can see the difference of the two images in the explorer.
I got a different header size when running the program.
The output:
============ Original one ===========
comments(origin) : no comment
Height(origin) : 534
Width(origin) : 800
Header Length(origin) : 21269
============ Copy one ===========
comments(copy) : no comment
Height(copy) : 534
Width(copy) : 800
Header Length(copy) : 603
Header Length is different as you can see the result.
Here is full test code.
package stackoverflow;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
public class Misc {
public static void main(String argv[]) throws IOException {
String imageFile1 = "resource/4.jpg";
String imageFile2 = "resource/4_jpg.jpg";
String imageFile3 = "resource/4_org.jpg";
fileCopy(imageFile1, imageFile3);
//copyImage(imageFile1);
ImageProperties origin = getJpegProperties(new File(imageFile1));
ImageProperties copyed = getJpegProperties(new File(imageFile2));
System.out.println("============ Original one ===========");
System.out.println("comments(origin) : " + origin.getComments());
System.out.println("Height(origin) : " + origin.getHeight());
System.out.println("Width(origin) : " + origin.getWidth());
System.out.println("Header Length(origin) : " + origin.getHeaderLen());
//System.out.println("suffix(origin) : " + origin.getSuffix());
System.out.println();
System.out.println("============ Copy one ===========");
System.out.println("comments(copy) : " + copyed.getComments());
System.out.println("Height(copy) : " + copyed.getHeight());
System.out.println("Width(copy) : " + copyed.getWidth());
System.out.println("Header Length(copy) : " + copyed.getHeaderLen());
//System.out.println("suffix(copy) : " + copyed.getSuffix());
}
static class ImageProperties {
private final int width;
private final int height;
private final String comments;
private final int headerLen;
private final String suffix;
public ImageProperties(
final int width, final int height, final String comments, final int headerLen,
final String suffix)
{
this.width = width;
this.height = height;
this.comments = comments;
this.suffix = suffix;
this.headerLen = headerLen;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public String getComments() {
return comments;
}
public String getSuffix() {
return suffix;
}
public int getHeaderLen() {
return headerLen;
}
}
final public static ImageProperties getJpegProperties(File file) throws FileNotFoundException, IOException {
BufferedInputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(file));
// check for "magic" header
byte[] buf = new byte[2];
int count = in.read(buf, 0, 2);
if (count < 2) {
throw new RuntimeException("Not a valid Jpeg file!");
}
if ((buf[0]) != (byte) 0xFF || (buf[1]) != (byte) 0xD8) {
throw new RuntimeException("Not a valid Jpeg file!");
}
int width = 0;
int height = 0;
char[] comment = null;
boolean hasDims = false;
boolean hasComment = false;
int ch = 0;
int totalHeaderLen = 0;
while (ch != 0xDA && !(hasDims && hasComment)) {
/* Find next marker (JPEG markers begin with 0xFF) */
while (ch != 0xFF) {
ch = in.read();
}
/* JPEG markers can be padded with unlimited 0xFF's */
while (ch == 0xFF) {
ch = in.read();
}
/* Now, ch contains the value of the marker. */
int length = 256 * in.read();
length += in.read();
totalHeaderLen += length;
if (length < 2) {
throw new RuntimeException("Not a valid Jpeg file!");
}
/* Now, length contains the length of the marker. */
if (ch >= 0xC0 && ch <= 0xC3) {
in.read();
height = 256 * in.read();
height += in.read();
width = 256 * in.read();
width += in.read();
for (int foo = 0; foo < length - 2 - 5; foo++) {
in.read();
}
hasDims = true;
} else if (ch == 0xFE) {
// that's the comment marker
comment = new char[length - 2];
for (int foo = 0; foo < length - 2; foo++)
comment[foo] = (char) in.read();
hasComment = true;
} else {
// just skip marker
for (int foo = 0; foo < length - 2; foo++) {
in.read();
}
}
}
if(comment == null) comment = "no comment".toCharArray();
return (new ImageProperties(width, height, new String(comment), totalHeaderLen, "jpeg"));
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
}
}
static BufferedImage copyImage(BufferedImage source) {
BufferedImage b = new BufferedImage(source.getWidth(), source.getHeight(), source.getType());
Graphics g = b.getGraphics();
g.drawImage(source, 0, 0, null);
g.dispose();
return b;
}
private static void fileCopy(String from, String to) {
FileChannel fromCh = null;
FileChannel toCh = null;
FileInputStream fin = null;
FileOutputStream fout = null;
try {
fin = new FileInputStream(new File(from));
fromCh = fin.getChannel();
fout = new FileOutputStream(new File(to));
toCh = fout.getChannel();
fromCh.transferTo(0, fin.available(), toCh);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fin != null)
try {
fin.close();
} catch (IOException e) {
}
if (fout != null)
try {
fout.close();
} catch (IOException e) {
}
}
}
}
So, I think the extra information of the jpeg image skipped by the image io library in java.

How to create an audio wave in JavaFX?

I would like to get an Audio wave plot using Chart Area in JavaFX. Unfortunately, I am not clear how to do, what are the values ​​to be extracted from the sound to assign to x-axis and y-axis?
I tried to read other posts, but I found nothing on javafx.
You can help me?
Sample Image:
Below is the code that extract the waveform .
I'm pulling out the right parameters for my scope?
How can I use it to print the graph with JavaFX?
public class SimpleWaveformExtractor implements WaveformExtractor {
private static final int DEFAULT_BUFFER_SIZE = 32768;
#Override
public double[] extract(File inputFile) {
AudioInputStream in = null;
try {
in = AudioSystem.getAudioInputStream(inputFile);
} catch (Exception e) {
System.out.println("Cannot read audio file");
return new double[0];
}
AudioFormat format = in.getFormat();
byte[] audioBytes = readBytes(in);
int[] result = null;
if (format.getSampleSizeInBits() == 16) {
int samplesLength = audioBytes.length / 2;
result = new int[samplesLength];
if (format.isBigEndian()) {
for (int i = 0; i < samplesLength; ++i) {
byte MSB = audioBytes[i * 2];
byte LSB = audioBytes[i * 2 + 1];
result[i] = MSB << 8 | (255 & LSB);
}
} else {
for (int i = 0; i < samplesLength; i += 2) {
byte LSB = audioBytes[i * 2];
byte MSB = audioBytes[i * 2 + 1];
result[i / 2] = MSB << 8 | (255 & LSB);
}
}
} else {
int samplesLength = audioBytes.length;
result = new int[samplesLength];
if (format.getEncoding().toString().startsWith("PCM_SIGN")) {
for (int i = 0; i < samplesLength; ++i) {
result[i] = audioBytes[i];
}
} else {
for (int i = 0; i < samplesLength; ++i) {
result[i] = audioBytes[i] - 128;
}
}
}
return ArraysHelper.normalize(result);
}
private byte[] readBytes(AudioInputStream in) {
byte[] result = new byte[0];
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
try {
int bytesRead = 0;
do {
bytesRead = in.read(buffer);
result = ArrayUtils.addAll(result, buffer);
} while (bytesRead != -1);
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
}
this is the interface:
public interface WaveformExtractor {
double[] extract(File in);
}
This is the code that return the array of double:
private double[] extractWaveform(File file) throws IOException, UnsupportedAudioFileException {
return new WavFileExtractor().extract(file);
}

External authentication in ejabberd using java

I am working on task to implement external authentication in ejabberd using java.
I searched for the examples on internet and found examples in PHP, Perl, Python but could not find any example in java.
I know the configuration that is required to be made in 'ejabberd.cfg' file.
Any code sample in java will be very helpful.
Try this:
public static void main(String[] args) {
try {
outerloop: while (true) {
byte[] lB = new byte[2];
int startPos = 0;
while (startPos < lB.length) {
int ret = System.in.read(lB, startPos,
(lB.length - startPos));
if (ret < 0) {
break outerloop;
}
startPos += ret;
}
int streamLen = System.in.available();
byte[] rd = new byte[streamLen];
startPos = 0;
while (startPos < streamLen) {
int ret = System.in.read(rd, startPos,
(streamLen - startPos));
if (ret < 0) {
break outerloop;
}
startPos += ret;
}
String inputArgs = new String(rd, "ASCII");
String[] arguments = inputArgs.split(":");
String userName = arguments[1];
String password = arguments[3];
//
// Here do the authentication
//
boolean resultOfAuthentication = // Result of Authentication;
byte[] res = new byte[4];
res[0] = 0;
res[1] = 2;
res[2] = 0;
if (resultOfAuthentication) {
res[3] = 1;
} else {
res[3] = 0;
}
System.out.write(res, 0, res.length);
System.out.flush();
}
} catch (Exception e) {
System.out.println("ERROR");
}
}

Categories

Resources