I am converting a input file (PDF,TIFF) to Output (TIFF) file by using PDFBox (PDF to BufferedImage) and using twelve monkeys for converting Buffered image to Tiff file by resizing using Imagewriter with IIOImage.
File is converting but losing an quality on the image.And after changed the imagetype BufferedImage.TYPE_BYTE_GRAY to BufferedImage.TYPE_BYTE_BINARY my text highlighters on the file lost.
Below is the code used. How to convert the image without losing quality?
I am converting the image file size 1648*2338 with 200 dpi and i wanted to set photometric interpretation to min_is_white but not able to achieve my problem.
File inputFile = new File(inputImagePath);
BufferedImage inputImage = ImageIO.read(inputFile);
final int imageType = BufferedImage.TYPE_BYTE_BINARY;
// creates output image
BufferedImage outputImage = new BufferedImage(scaledWidth, scaledHeight,imageType);
// scales the input image to the output image
Graphics2D g2d = outputImage.createGraphics();
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose();
// writes to output file
final List<Entry> entries =new ArrayList<Entry>();
entries.add(new TIFFEntry(TIFF.TAG_X_RESOLUTION, new Rational(200)));
entries.add(new TIFFEntry(TIFF.TAG_Y_RESOLUTION, new Rational(200)));
entries.add(new TIFFEntry(TIFF.TAG_PHOTOMETRIC_INTERPRETATION, TIFF.TYPE_SHORT, 0));
final IIOMetadata tiffImageMetadata =new TIFFImageMetadata(entries);
ImageWriter writer = ImageIO.getImageWritersByFormatName("tiff").next();
FileImageOutputStream fio = new FileImageOutputStream(new File(outputImagePath));
ImageWriteParam params = writer.getDefaultWriteParam();
params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
fio.setByteOrder(ByteOrder.LITTLE_ENDIAN);
IIOMetadata metadata = writer.getDefaultImageMetadata(new ImageTypeSpecifier(outputImage), params);
writer.setOutput(fio);
IIOImage iioimage = new IIOImage(outputImage, null, tiffImageMetadata);
writer.write(null, iioimage, params);
fio.close();
writer.dispose();
Related
I would like to know if it is possible to convert mp3 to wave using nAudio library but without saving converted file to disc (using for example MemoeryStream) ?
Link to nAudio
Any examples?
I tried like this:
byte[] fileStream = null;
MemoryStream ms2 = new MemoryStream();
using (WaveStream waveStream = WaveFormatConversionStream.CreatePcmStream(newMp3FileReader(filePath)))
using (WaveFileWriter waveFileWriter = new WaveFileWriter(ms2,waveStream.WaveFormat))
{
byte[] bytes3 = new byte[waveStream.Length];
waveStream.Position = 0;
waveStream.Read(bytes3, 0, (int)waveStream.Length);
waveFileWriter.Write(bytes3, 0, bytes3.Length);
fileStream = bytes3;
return fileStream;
}
When I saved file from byte array it is damaged.
Screen:
The simplest way to do it is to pass a MemoryStream instance to WaveFileWriter constructor, then write all the samples to the writer... For the decoding side you can use the Mp3FileReader...
Good luck!
I want to add a limit on uploaded image size (currently images are uploaded to a server).
When anyone gets an image from SDcard or captures image from Camera, I want show message to user that it uploaded max file size - i.e 500kb or can I resize images into smaller sizes. For example 1mb image resize into 400-500kb (like Facebook).
Here is the sample code that I implemented after getting image from SDcard or captured image from Camera.
FileConnection file = (FileConnection)Connector.open(url);
if(file.exists())
{
try{
String fileName = url .substring(url.lastIndexOf('/') + 1);
//String fileName = url ;
Dialog.alert("fileName " + fileName);
InputStream inputStream = file.openInputStream();
ByteArrayOutputStream bos=new ByteArrayOutputStream();
int buffersize=1024;
byte[] buffer=new byte[buffersize];
int length=0;
while((length=inputStream.read(buffer))!=-1)
{
bos.write(buffer,0,length);
}
byte[] imagedata=bos.toByteArray();
Dialog.alert("Url " + Url + " Image Data Byte " + imagedata);
HttpConnection conn = (HttpConnection) Connector.open(Url, Connector.READ_WRITE);
conn.setRequestMethod(HttpConnection.POST);
String boundary = "Some_Unique_Text_Also_Alphanumeric";
conn.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_TYPE,
HttpProtocolConstants.CONTENT_TYPE_MULTIPART_FORM_DATA
+ ";boundary=" + boundary);
conn.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_LENGTH,
String.valueOf(imagedata.length));
conn.setRequestProperty("x-rim-transcode-content", "none");
ByteArrayOutputStream out = new ByteArrayOutputStream();
OutputStream finalOut = conn.openOutputStream();
String newLine = "\r\n";
out.write(newLine.getBytes());
out.write("--".getBytes());
out.write(boundary.getBytes());
out.write(newLine.getBytes());
String contDisp = "Content-Disposition:form-data;name=\"image\";fileName=\"Image.jpg\"";
String contEnc = "Content-Transfer-Encoding: binary";
String contentType = "Content-Type:image/jpeg";
out.write(contDisp.getBytes());
out.write(newLine.getBytes());
out.write(contentType.getBytes());
out.write(newLine.getBytes());
out.write(contEnc.getBytes());
out.write(newLine.getBytes());
out.write(newLine.getBytes());
out.write(imagedata);
out.write(newLine.getBytes());
out.write("--".getBytes());
out.write(boundary.getBytes());
out.write("--".getBytes());
out.write(newLine.getBytes());
finalOut.write(out.toByteArray());
out.flush();
out.close();
finalOut.flush();
finalOut.close();
InputStream instream=conn.openInputStream();
int ch=0;
StringBuffer buffesr=new StringBuffer();
while((ch=instream.read())!=-1)
{
buffesr.append((char)ch);
Dialog.alert("Uploaded");
}
}
catch (Exception e) {
Dialog.alert("Exception " + e);
}
}
Any help ??
The problem is that with Camera pictures, you can't predict what physical image size (pixel width x height) will correspond to a certain size in bytes.
If you have a hard, fixed limit on the size (in bytes) that you can upload, you might need to do something like this:
experiment with a few images, and find an approximate image size (width x height) that will produce a JPG file that normally fits within your 400-500KB limit
in your app, resize the Camera images to that physical size (width x height, in pixels)
check the size of the new JPG data, and see if it fits under your limit
if it does not fit, then you'll have to rescale the original image to a smaller size
As you can see, this isn't that simple to do. Most servers that I've seen (e.g. Facebook) tell you the maximum physical size in pixels that your image can be (e.g. 960 pixels as the widest size ... either width or height). If that's good enough for your server, it's much easier to code on the BlackBerry client side.
Restrict to a Fixed Pixel Width and Height
You could use something like this:
FileConnection file;
InputStream inputStream;
try {
file = (FileConnection) Connector.open(url); // JPG file:// URL
if (file.exists())
{
inputStream = file.openInputStream();
byte[] data = IOUtilities.streamToBytes(inputStream);
Bitmap original = Bitmap.createBitmapFromBytes(data, 0, data.length, 1);
Bitmap scaledImg = new Bitmap(640, 480); // maximum width and height
original.scaleInto(scaledImg,
Bitmap.FILTER_LANCZOS, /* LANCZOS is for best quality */
Bitmap.SCALE_TO_FIT);
// http://stackoverflow.com/a/14147236/119114
int jpegQuality = 85;
EncodedImage encodedImg = JPEGEncodedImage.encode(scaledImg, jpegQuality);
byte[] imageData = encodedImg.getData();
// TODO: send imageData as you already were
}
} catch (Exception e) {
// log exception
} finally {
try {
if (file != null) {
file.close();
}
if (inputStream != null) {
inputStream.close();
}
} catch (IOException ioe) {
// nothing can be done here
}
}
Of course, you should perform all this work on a background thread. Once you know the final image size, if you really want to, you can notify the user with something like:
final uploadSizeKb = imageData.length / 1024;
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert(uploadSizeKb + "KB uploaded to server");
}
});
Further Optimizations
As you can probably tell, there's things you can adjust with this algorithm:
You could optimize by checking to see if the image file is already small enough, before trying to scale it. (check file.fileSize())
You could speed up the image scaling by using Bitmap.FILTER_BILINEAR or Bitmap.FILTER_BOX instead of Bitmap.FILTER_LANCZOS.
You can change the JPEG quality factor from 85 when you convert back to JPEG for uploading
You might need to check image orientation to avoid wasting too much space when you scale with SCALE_TO_FIT. If the Camera image is in the wrong orientation, just switch the scaledImg bitmap width and height (e.g. 640x480 -> 480x640)
You actually can skip a couple steps, and scale directly when reading in the image file, with createBitmapFromBytes(). The last parameter is a scale parameter. Unfortunately, since photographs are all different, it would also be difficult to pick one scale ratio that would work. As I said, it's more common that the server simply specifies a maximum image size, in pixels.
OS < 5.0 Support
If you don't have the image scaling APIs in OS 5.0 available, this older toolkit can be useful.
I am trying to save an OpenCV image to the hard drive.
Here is what I tried:
public void SaveImage (Mat mat) {
Mat mIntermediateMat = new Mat();
Imgproc.cvtColor(mRgba, mIntermediateMat, Imgproc.COLOR_RGBA2BGR, 3);
File path =
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
String filename = "barry.png";
File file = new File(path, filename);
Boolean bool = null;
filename = file.toString();
bool = Highgui.imwrite(filename, mIntermediateMat);
if (bool == true)
Log.d(TAG, "SUCCESS writing image to external storage");
else
Log.d(TAG, "Fail writing image to external storage");
}
}
Can any one show how to save that image with OpenCV 2.4.3?
Your question is a bit confusing, as your question is concerning OpenCV on the desktop, but your code is for Android, and you ask about IplImage, but your posted code is using C++ and Mat. Assuming you're on the desktop using C++, you can do something along the lines of:
cv::Mat image;
std::string image_path;
//load/generate your image and set your output file path/name
//...
//write your Mat to disk as an image
cv::imwrite(image_path, image);
...Or for a more complete example:
void SaveImage(cv::Mat mat)
{
cv::Mat img;
cv::cvtColor(...); //not sure where the variables in your example come from
std::string store_path("..."); //put your output path here
bool write_success = cv::imwrite(store_path, img);
//do your logging...
}
The image format is chosen based on the supplied filename, e.g. if your store_path string was "output_image.png", then imwrite would save it was a PNG image. You can see the list of valid extensions at the OpenCV docs.
One caveat to be aware of when writing images to disk with OpenCV is that the scaling will differ depending on the Mat type; that is, for floats the images are expected to be within the range [0, 1], while for say, unsigned chars they'll be from [0, 256).
For IplImages, I'd advise just switching to use Mat, as the old C-interface is deprecated. You can convert an IplImage to a Mat via cvarrToMat then use the Mat, e.g.
IplImage* oldC0 = cvCreateImage(cvSize(320,240),16,1);
Mat newC = cvarrToMat(oldC0);
//now can use cv::imwrite with newC
alternately, you can convert an IplImage to a Mat just with
Mat newC(oldC0); //where newC is a Mat and oldC0 is your IplImage
Also I just noticed this tutorial at the OpenCV website, which gives you a walk-though on loading and saving images in a (desktop) environment.
I want to send the image stored in the RMS to server. For that I have stored the captured image in the RMS. I can access it successfully and can show it over device, but when I used to send it to server, that time over the server only name of image appears but the image is not generating.
here is the line code that I am trying to use
byte[] byteArrRec = LoadImagesFromRMS.objImageRecordStore.getRecord(recID);
ByteArrayInputStream bin = new ByteArrayInputStream(byteArrRec);
DataInputStream din = new DataInputStream(bin);
int width = din.readInt();
int height = din.readInt();
int length = din.readInt();
int[] rawImg = new int[width * height];
for (int itemp = 0; itemp < length; itemp++) {
rawImg[itemp] = din.readInt();
}
Image tempImage = Image.createRGBImage(rawImg, width, height, false);
byteArr = get_Byte_Array(tempImage);
byteArr = get_Byte_Array(tempImage);
Then I have passed the byteArray using post method over the server.
But the Image is not been generated, Did any one have any idea about this?
First need to read all bytes from response and store in one variable (bytearray) of byte array. Then after that write this code
Create a ByteArrayInputStream from your byte array and then use ImageIO class to read image from that stream.
InputStream in = new ByteArrayInputStream(bytearray);
BufferedImage image = ImageIO.read(in);
Thanks
you need to create HttpConnection with the remote server, after creating connection , create a DataOutputStream variable associated with the HttpConnection variable.
Now write byte array into that DataOutputStream variable and send it as "POST" method. If byte array's size is very big the try to send it in chunks..
I saw the sample APIas below
public static byte[] compress( byte[] data )
{
try
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzipStream = new GZIPOutputStream( baos, 6, GZIPOutputStream.MAX_LOG2_WINDOW_LENGTH );
gzipStream.write( data );
gzipStream.close();
}
catch(IOException ioe)
{
return null;
}
return baos.toByteArray();
}
But when I tried to compress with a large file with Curve 8900 OS 4.6, I got a "OutOfMemoryError" so I would like to know that how to compress as a chunk small data?
I already tried with this code as below but it doesn't work, compressed file cannot decompress...
file = (FileConnection)Connector.open(_fileOutputPath, Connector.READ_WRITE);
if (!file.exists()) {
file.create();
}
os = file.openOutputStream();
is = FileUtil.getInputStream(_fileInputPath, 0);
int tmpSize = 1024;
byte[] tmp = new byte[tmpSize];
int len = -1;
gzipStream = new GZIPOutputStream( os, 6, GZIPOutputStream.MAX_LOG2_WINDOW_LENGTH );
while((len = is.read(tmp, 0, tmpSize)) != -1) {
gzipStream.write(tmp, 0, len);
}
GZIPOutputStream does not produce a file suitable for use with the gzip command line tool. This is because it doesn't produce the necessary file headers. How did you test decompressing it? You should write a similar Java program that makes use of GZIPInputStream to test, as 'gunzip' is not going to recognize the input.
The problem of the first code sample is that the ByteArrayOutputStream is getting too big for the limited memory of a mobile device.
An option could be to first write to a file (for instance) on SD card.
The second code sample seems fine, but see Michael's answer.