I am working a method to resize featured image and I have finished it, but after testing seems something isn't right cause the image is deformed and don't look nice at all, I am looking very carefully, but I don't get to see what's the problem, I would really appreciate if you have any idea what is wrong or a better way to solve this. Have a look please, I would really need some better advice and thanks in advance!!
private byte[] resizeFeatureImage(MultipartFile featureImage)
{
try
{
BufferedImage originalImage = ImageIO.read(featureImage.getInputStream());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
double featImageWidth = originalImage.getWidth();
double featImageHeight = originalImage.getHeight();
if (featImageHeight > MAX_FEAT_IMAGE_HEIGHT || featImageWidth > MAX_FEAT_IMAGE_WIDTH)
{
// Sanity check on the input (division by zero, infinity):
if (featImageWidth <= 1 || featImageHeight <= 1)
{
throw new IllegalArgumentException("Cannot do image resize for " + featureImage);
}
// The scaling factors to reach to max on WIDTH and HEIGHT:
double xScale = MAX_FEAT_IMAGE_WIDTH / featImageWidth;
double yScale = MAX_FEAT_IMAGE_HEIGHT / featImageHeight;
// Proportional (scale WIDTH and HEIGHT by the same factor):
double scale = Math.min(xScale, yScale);
// (Possibly) Do not enlarge:
scale = Math.min(1.0, scale);
int finalWidth = Math.min((int) Math.round(scale * featImageWidth), MAX_FEAT_IMAGE_WIDTH);
int finalHeight = Math.min((int) Math.round(scale * featImageHeight), MAX_FEAT_IMAGE_HEIGHT);
double ratio = featImageWidth / featImageHeight;
// WIDTH is bigger then HEIGHT
if (ratio > 1)
{
finalWidth = MAX_FEAT_IMAGE_WIDTH;
finalHeight = (int) Math.round(MAX_FEAT_IMAGE_HEIGHT / ratio);
}
// HEIGHT is bigger then WIDTH
else if (ratio < 1)
{
finalWidth = (int) Math.round(MAX_FEAT_IMAGE_WIDTH / ratio);
finalHeight = MAX_FEAT_IMAGE_HEIGHT;
}
// WIDTH and HEIGHT are equal
else
{
finalHeight = MAX_FEAT_IMAGE_HEIGHT;
finalWidth = MAX_FEAT_IMAGE_WIDTH;
}
logger.info("[resizeFeatureImage] [FEATURE IMAGE RESIZE] Starting to resize feature Image");
Graphics2D g2d;
BufferedImage resizedImage;
if (featureImage.getContentType().contains("png"))
{
resizedImage = new BufferedImage(finalWidth, finalHeight, BufferedImage.TYPE_INT_ARGB);
}
else
{
resizedImage = new BufferedImage(finalWidth, finalHeight, BufferedImage.TYPE_3BYTE_BGR);
}
g2d = resizedImage.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.drawImage(ImageIO.read(featureImage.getInputStream()), 0, 0, finalWidth, finalHeight,
null);
g2d.dispose();
ImageIO.write(resizedImage, featureImage.getContentType().split("/")[1], baos);
logger.info("[resizeFeatureImage] [FEATURE IMAGE RESIZE] Feature image resized!");
return baos.toByteArray();
}
else
{
ImageIO.write(originalImage, featureImage.getContentType().split("/")[1], baos);
return baos.toByteArray();
}
}
catch (Exception e)
{
logger.warn("[resizeFeatureImage] [STATUS] - ERROR ");
logger.warn("[resizeFeatureImage] [EXCEPTION] " + e.getMessage(), e);
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
"The file you uploaded can be damaged or has incorrect encoding.");
}
}
When you scale, your image needs to retain the same ratio.
double featImageWidth = originalImage.getWidth();
double featImageHeight = originalImage.getHeight();
double ratio = featImageWidth/featImageHeight;
//this width meets your constraints
int finalWidth = MAX_FEAT_IMAGE_WIDTH;
//this final height is what the height would be to keep the same ratio.
int finalHeight = (int)(finalWidth/ratio);
if(finalHeight > MAX_FEAT_IMAGE_HEIGHT){
//the height constrains the image.
finalHeight = MAX_FEAT_IMAGE_HEIGHT;
finalWidth = (int)(finalHeight*ratio)
}
Related
Please re-read my question before a vote, I want to add an icon or png image to a screenshot image immediately after taking
I don't know is it a good approach or not, but I tried this
private static Bitmap addWaterMark(Bitmap src, Context context, String waterMarkImage) {
int w = src.getWidth();
int h = src.getHeight();
Bitmap result = Bitmap.createBitmap(w, h, src.getConfig());
Canvas canvas = new Canvas(result);
canvas.drawBitmap(src, 0, 0, null);
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
int width = metrics.widthPixels;
int height = metrics.heightPixels;
Log.d(TAG, "Width X Height " + width + " X " + height);
Point point = new Point();
display.getSize(point);
int maxX = point.x;
int maxY = point.y;
point.set(maxX, maxY);
int maxWidth = (70 * width) / 100;
int maxHeight = (80 * height) / 100;
Log.d(TAG, "maxWidth X maxHeight " + maxWidth + " X " + maxHeight);
Bitmap waterMark = null;
if (waterMarkImage != null) {
byte[] decodedByte = Base64.decode(waterMarkImage, 0);
waterMark = BitmapFactory.decodeByteArray(decodedByte, 0, decodedByte.length);
waterMark = Bitmap.createScaledBitmap(waterMark, 250, 250, true);
} else {
waterMark = BitmapFactory.decodeResource(context.getResources(), R.drawable.sharelogo1);
}
canvas.drawBitmap(waterMark, maxWidth, maxHeight, null);
return result;
}
and it's working fine but watermark image size and position is not working as I want (not supporting all screen sizes or resolutions)
In your code snippet change
waterMark = Bitmap.createScaledBitmap(waterMark, 250, 250, true);
by
waterMark = Bitmap.createScaledBitmap(waterMark, getpixels(250), getpixels(250), true);
And add below method in to convert dp to pixel
private float getpixels(float dipValue) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, Resources.getSystem().getDisplayMetrics());
}
i've really searched through over the entire web before posting. My problem is that i cannot resize bitmap without losing the quality of the image (the quality is really bad and pixelated).
I take the bitmap from camera and then i have to downscale it, so i can upload it to the server much faster.
This is the function that does the sampling
public Bitmap resizeBitmap(Bitmap bitmap){
Canvas canvas = new Canvas();
Bitmap resizedBitmap = null;
if (bitmap !=null) {
int h = bitmap.getHeight();
int w = bitmap.getWidth();
int newWidth=0;
int newHeight=0;
if(h>w){
newWidth = 600;
newHeight = 800;
}
if(w>h){
newWidth = 800;
newHeight = 600;
}
float scaleWidth = ((float) newWidth) / w;
float scaleHeight = ((float) newHeight) / h;
Matrix matrix = new Matrix();
// resize the bit map
matrix.preScale(scaleWidth, scaleHeight);
resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawBitmap(resizedBitmap, matrix, paint);
}
return resizedBitmap;
and this is how i get the image from activity result
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
if(resultCode != RESULT_CANCELED){
if (requestCode == 0) {
if (resultCode == RESULT_OK) {
getContentResolver().notifyChange(mImageUri, null);
ContentResolver cr = this.getContentResolver();
try
{
b = android.provider.MediaStore.Images.Media.getBitmap(cr, mImageUri);
Log.d("foto", Integer.toString(b.getWidth()));
Log.d("foto", Integer.toString(b.getHeight()));
addPhoto.setImageBitmap(b);
}
catch (Exception e)
{
Toast.makeText(this, "Failed to load", Toast.LENGTH_SHORT).show();
Log.d("TAG", "Failed to load", e);
}
}
}
I'm starting to think that the best way to get a small picture size is to set the camera resolution. Anyone else can help?
Good downscaling algorithm (not nearest neighbor like) consists of just 2 steps (plus calculation of the exact Rect for input/output images crop):
downscale using BitmapFactory.Options::inSampleSize->BitmapFactory.decodeResource() as close as possible to the resolution that you need but not less than it
get to the exact resolution by downscaling a little bit using Canvas::drawBitmap()
Here is detailed explanation how SonyMobile resolved this task: http://developer.sonymobile.com/2011/06/27/how-to-scale-images-for-your-android-application/
Here is the source code of SonyMobile scale utils: http://developer.sonymobile.com/downloads/code-example-module/image-scaling-code-example-for-android/
Try below mentioned code for resizing bitmap.
public Bitmap get_Resized_Bitmap(Bitmap bmp, int newHeight, int newWidth) {
int width = bmp.getWidth();
int height = bmp.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// CREATE A MATRIX FOR THE MANIPULATION
Matrix matrix = new Matrix();
// RESIZE THE BIT MAP
matrix.postScale(scaleWidth, scaleHeight);
// "RECREATE" THE NEW BITMAP
Bitmap newBitmap = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix, false);
return newBitmap ;
}
I used this code to downsize my bitmap, and its quality, well.. , was acceptable.
Hope this helps.
Try Bitmap.createScaledBitmap.
It also has an option to filter the source.
the best rescaling method I have come across
the method uses createScaledBitmap whereby the height and width are calculated based on the bitmap height and width and a scale ratio hence quality is not lost
public Bitmap resize(Bitmap imaged, int maxWidth, int maxHeight) {
Bitmap image = imaged;
if (maxHeight > 0 && maxWidth > 0) {
int width = image.getWidth();
int height = image.getHeight();
float ratioBitmap = (float) width / (float) height;
float ratioMax = (float) maxWidth / (float) maxHeight;
int finalWidth = maxWidth;
int finalHeight = maxHeight;
if (ratioMax > 1) {
finalWidth = Math.round(((float) maxHeight * ratioBitmap));
} else {
finalHeight = Math.round(((float) maxWidth / ratioBitmap));
}
return image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, false);
}
return image;
}
how to use:
Bitmap resizedBitmap = resize(scrBitMap,640,640);
In the script it is going from around the 300x300 mark down to 60x60. Need to improve the overall image quality as it is coming out very poorly at the moment.
public static Boolean resizeImage(String sourceImg, String destImg, Integer Width, Integer Height, Integer whiteSpaceAmount)
{
BufferedImage origImage;
try
{
origImage = ImageIO.read(new File(sourceImg));
int type = origImage.getType() == 0? BufferedImage.TYPE_INT_ARGB : origImage.getType();
int fHeight = Height;
int fWidth = Width;
int whiteSpace = Height + whiteSpaceAmount; //Formatting all to squares so don't need two whiteSpace calcs..
double aspectRatio;
//Work out the resized dimensions
if (origImage.getHeight() > origImage.getWidth()) //If the pictures height is greater than the width then scale appropriately.
{
fHeight = Height; //Set the height to 60 as it is the biggest side.
aspectRatio = (double)origImage.getWidth() / (double)origImage.getHeight(); //Get the aspect ratio of the picture.
fWidth = (int)Math.round(Width * aspectRatio); //Sets the width as created via the aspect ratio.
}
else if (origImage.getHeight() < origImage.getWidth()) //If the pictures width is greater than the height scale appropriately.
{
fWidth = Width; //Set the height to 60 as it is the biggest side.
aspectRatio = (double)origImage.getHeight() / (double)origImage.getWidth(); //Get the aspect ratio of the picture.
fHeight = (int)Math.round(Height * aspectRatio); //Sets the height as created via the aspect ratio.
}
int extraHeight = whiteSpace - fHeight;
int extraWidth = whiteSpace - fWidth;
BufferedImage resizedImage = new BufferedImage(whiteSpace, whiteSpace, type);
Graphics2D g = resizedImage.createGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, whiteSpace, whiteSpace);
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(origImage, extraWidth/2, extraHeight/2, fWidth, fHeight, null);
g.dispose();
ImageIO.write(resizedImage, "jpg", new File(destImg));
}
catch (IOException ex)
{
return false;
}
return true;
}
Really just need to know if their is something I can plug in that will bump up the quality or if I need to look at something else entirely.
EDIT: Picture comparison.
Source, just picked a random washing machine from google.
http://www.essexappliances.co.uk/images/categories/washing-machine.jpg
The same picture converted in Photoshop to what I need it to be.
http://imgur.com/78B1p
What it looks like being converted like this.
http://imgur.com/8WlXD
Scaling an image down over a large range is inherently dangerous (from the point of view of quality), especially using a single step.
The recommended method is to use a divide and conquer method. Basically, you scale the image down in steps of 50% until you reach your desired size.
So, I took the original image of 650x748 and scaled it down to fit within a 60x60 region (52x60).
Divide and conquer compared to one step...
public class TestImageResize {
public static void main(String[] args) {
new TestImageResize();
}
public TestImageResize() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new ScalePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ScalePane extends JPanel {
private BufferedImage original;
private BufferedImage scaled;
public ScalePane() {
try {
original = ImageIO.read(new File("path/to/master.jpg"));
scaled = getScaledInstanceToFit(original, new Dimension(60, 60));
ImageIO.write(scaled, "jpg", new File("scaled.jpg"));
BufferedImage image = new BufferedImage(52, 60, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = image.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawImage(original, 0, 0, 52, 60, this);
g2d.dispose();
ImageIO.write(image, "jpg", new File("test.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
if (original != null) {
if (scaled != null) {
size.width = original.getWidth() + scaled.getWidth();
size.height = original.getHeight();
} else {
size.width = original.getWidth();
size.height = original.getHeight();
}
}
return size;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (original != null) {
int x = 0;
int y = (getHeight() - original.getHeight()) / 2;;
if (scaled != null) {
x = (getWidth() - (original.getWidth() + scaled.getWidth())) / 2;
} else {
x = (getWidth() - original.getWidth()) / 2;
}
g2d.drawImage(original, x, y, this);
if (scaled != null) {
x += original.getWidth();
y = (getHeight() - scaled.getHeight()) / 2;
g2d.drawImage(scaled, x, y, this);
}
}
g2d.dispose();
}
public BufferedImage getScaledInstanceToFit(BufferedImage img, Dimension size) {
float scaleFactor = getScaleFactorToFit(img, size);
return getScaledInstance(img, scaleFactor);
}
public float getScaleFactorToFit(BufferedImage img, Dimension size) {
float scale = 1f;
if (img != null) {
int imageWidth = img.getWidth();
int imageHeight = img.getHeight();
scale = getScaleFactorToFit(new Dimension(imageWidth, imageHeight), size);
}
return scale;
}
public float getScaleFactorToFit(Dimension original, Dimension toFit) {
float scale = 1f;
if (original != null && toFit != null) {
float dScaleWidth = getScaleFactor(original.width, toFit.width);
float dScaleHeight = getScaleFactor(original.height, toFit.height);
scale = Math.min(dScaleHeight, dScaleWidth);
}
return scale;
}
public float getScaleFactor(int iMasterSize, int iTargetSize) {
float scale = 1;
if (iMasterSize > iTargetSize) {
scale = (float) iTargetSize / (float) iMasterSize;
} else {
scale = (float) iTargetSize / (float) iMasterSize;
}
return scale;
}
public BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {
BufferedImage imgBuffer = null;
imgBuffer = getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
return imgBuffer;
}
protected BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint, boolean higherQuality) {
int targetWidth = (int) Math.round(img.getWidth() * dScaleFactor);
int targetHeight = (int) Math.round(img.getHeight() * dScaleFactor);
int type = (img.getTransparency() == Transparency.OPAQUE)
? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
if (targetHeight > 0 || targetWidth > 0) {
int w, h;
if (higherQuality) {
w = img.getWidth();
h = img.getHeight();
} else {
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
} else {
ret = new BufferedImage(1, 1, type);
}
return ret;
}
}
}
You may, also, find The Perils of Image.getScaledInstance() of interest.
The issue you are seeing is actually related to the resampling filter used for downscaling. Obviously, the one used by your library is a bad one for the situation. Nearest neighbor, bilinear and bicubic are typical bad examples to be used when downscaling. I don't know the exact resampling filter Photoshop uses, but I used 3-lobed lanczos and got the following result:
So, to solve your problem, you need to use a smarter resampling filter.
dutchman, this is why I maintain the imgscalr library -- to make this kind of stuff painfully easy.
In your example, a single method call would do the trick, right after your first ImageIO.read line:
origImage = ImageIO.read(new File(sourceImg));
you can do the following to get what you want (javadoc for this method):
origImage = Scalr.resize(origImage, Method.ULTRA_QUALITY, 60);
and if that still looked a little jagged (because you are removing so much information from the image, you can add the following OP to the command to apply a light anti-aliasing filter to the image so it looks smoother):
origImage = Scalr.resize(origImage, Method.ULTRA_QUALITY, 60, Scalr.OP_ANTIALIAS);
That will replace all the remainder of the code logic you have. The only other thing I would recommend is saving out your really small samples as PNG's so there is no more compression/lossy conversion done on the image OR make sure you use little to none compression on the JPG if you really want it in JPG format. (Here is an article on how to do it; it utilizes the ImageWriteParam class)
imgscalr is licensed under an Apache 2 license and hosted on GitHub so you can do what you want with it; it also includes asynchronous scaling support if you are using the library in a server-side app and queuing up huge numbers of scaling operations and don't want to kill the server.
As already stated, Java's Graphics2D does not provide a very good algorithm for down-scaling. If you don't want to implement a sophisticated algorithm yourself you could try out the current open source libs specialized for this: Thumbnailator, imgscalr and a Java interface for ImageMagick.
While researching for a private project I tried them out (except ImageMagick) and here are the visual results with Photoshop as reference:
A. Thumbnailator 0.4.8 with default settings (no additional internal resizing)
B. imgscalr 4.2 with ULTRA_QUALTY setting
C. Photoshop CS5 bicubic filter (save for web)
D. Graphics2d with all HQ render hints
Here is the used code
Thumbnailator and PS create similar results, while imgscalr seems to be softer. It is subjective which one of the libs creates the preferable results. Another point to consider though is the performance. While Thumbnailator and Graphics2d have similar runtime, imgscalr is considerably slower (with ULTRA_QUALITY) in my benchmarks.
For more info, read this post providing more detail on this matter.
I tried the code below to generate a thumbnail.
I am able to get the thumbnail but the quality is not there. Please can any one help me in this one to generate a high quality thumbnail? The original image is high quality.
BufferedImage thumbImage = new BufferedImage(thumbWidth, thumbHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = thumbImage.createGraphics();
graphics2D.setBackground(Color.WHITE);
graphics2D.setPaint(Color.WHITE);
graphics2D.fillRect(0, 0, thumbWidth, thumbHeight);
graphics2D.setComposite(AlphaComposite.Src);
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.drawImage(image, 0, 0, thumbWidth, thumbHeight, null);
graphics2D.dispose();
File file = new File(thumbnailFile);
if (javax.imageio.ImageIO.write(thumbImage, "JPG", file))
return file;
You might want to take a look at this: http://download.oracle.com/javase/tutorial/uiswing/components/icon.html
http://download.oracle.com/javase/tutorial/uiswing/examples/components/IconDemoProject/src/components/IconDemoApp.java
I used that as a reference for doing something similar before.
I had the same problem and found this great article with sample code and sample images at the end:
http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html
check this I found best jar file here
public static javaxt.io.Image resizeThumbnailImage(javaxt.io.Image image, int width, int height) {
Integer imgWidth = image.getWidth();
Integer imgHeight = image.getHeight();
Double imgRatio = (imgWidth.doubleValue() / imgHeight.doubleValue());
logger.info("\n======= imgRatio " + imgRatio);
if (imgRatio >= 2) {
image.setWidth(width - 1);
} else if (imgRatio < 1) {
image.setHeight(300);
} else {
Double expectedHeight = (imgRatio * (height / ProjectConstant.THUMBNAIL_IMG_ASPECT_RATIO));
image.setHeight(expectedHeight.intValue());
if (image.getWidth() > width) {
image.setWidth(width - 20);
}
}
logger.info("=======after Processing image Width " + image.getWidth()+" Hight "+image.getHeight());
return image;
}
my constant
public static final double THUMBNAIL_IMG_ASPECT_RATIO = 1.4;
I am a newbie to graphics. I've been using this code to make thumbnails of image files. When i use small files(~100KB) like wall papers, it works fine but when i use an image file(a photo) of size ~5MB, it produces just a few bytes(~1-8KB) of file which shows up as black image. It does not matter what Width and Height i give it. What could be going wrong here? Is it a difference between image types or the camera that produces the images? I'm sure the problem images are from a different camera than the non problematic ones. I am giving quality param as 100 to not miss out any detail that way...
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
int dx = thumbWidth, dy = thumbHeight;
Image image = Toolkit.getDefaultToolkit().createImage(file);
MediaTracker mediaTracker = new MediaTracker(new Container());
mediaTracker.addImage(image, 0);
mediaTracker.waitForID(0);
double thumbRatio = (double)thumbWidth / (double)thumbHeight;
int imageWidth = image.getWidth(null);
int imageHeight = image.getHeight(null);
double imageRatio = (double)imageWidth / (double)imageHeight;
if (thumbRatio < imageRatio) {
thumbHeight = (int)(thumbWidth / imageRatio);
} else {
thumbWidth = (int)(thumbHeight * imageRatio);
}
if(thumbWidth > dx) {
thumbWidth = dx;
thumbHeight = (int)(thumbWidth / imageRatio);
}
if(thumbHeight > dy)
{
thumbHeight = dy;
thumbWidth = (int) (thumbHeight*imageRatio);
}
log.debug("X="+thumbWidth+" Y="+thumbHeight);
BufferedImage thumbImage = new BufferedImage(thumbWidth, thumbHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = thumbImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics2D.drawImage(image, 0, 0, thumbWidth, thumbHeight, null);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(thumbImage);
quality = Math.max(0, Math.min(quality, 100));
param.setQuality((float)quality / 100.0f, false);
encoder.setJPEGEncodeParam(param);
encoder.encode(thumbImage);
log.debug("ThumbLength"+out.toByteArray().length);
FileOutputStream fos = new FileOutputStream("/root/testx.jpg");
fos.write(out.toByteArray());
fos.close();
} catch(Exception e) { log.debug(e.getMessage());}
return out.toByteArray();
You might try BufferedImage.TYPE_INT_ARGB, as shown here.
Also, your MediaTracker is waiting on the same thread; ImageIO.read() might be simpler.
Addendum: Also consider AffineTransformOp, although the src and dst must be different.