2016-06-08 2 views
0

Иногда мои изображения являются слишком большими, и я получаю эту ошибку:Изменить размер на самом большие возможные изображения при mantaining соотношения

Exception in thread "main" java.lang.NegativeArraySizeException at java.awt.image.DataBufferByte.(Unknown Source) at java.awt.image.Raster.createInterleavedRaster(Unknown Source) at java.awt.image.BufferedImage.(Unknown Source)

Всякий раз, когда я получаю это я хочу, чтобы настроить мое изображение до максимально возможного размера, сохраняя при этом соотношении ,

я в конечном итоге со следующими формулами:

if (targetWidth * targetHeight >= Integer.MAX_VALUE || targetWidth * targetHeight < 0) { 
     System.out.println("Target image too big... Size will be adjusted!"); 
     if (targetWidth > targetHeight) { 
      targetWidth = (int)Math.sqrt((Integer.MAX_VALUE) * (float)(targetWidth/targetHeight)); 
      targetHeight = (Integer.MAX_VALUE)/targetWidth; 
     } else { 
      targetHeight = (int)Math.sqrt((Integer.MAX_VALUE) * (float)(targetHeight/targetWidth)); 
      targetWidth = (Integer.MAX_VALUE)/targetHeight; 
     } 
    } 

я все еще получаю ту же проблему, и мои условия. Я предполагаю, что

WIDTH * HEIGHT < Integer.MAX_VALUE

ли явно не условие Ищу Любая помощь?

Edit: После некоторого обсуждения я думаю, что реальный вопрос к этой проблеме: Какой самый большой возможный размер, который я могу передать в конструктор BufferedImage для того, чтобы не получить NegativeArraySizeException на:

at java.awt.image.DataBufferByte.(Unknown Source)

+0

Проверьте это для размера массива: http://stackoverflow.com/questions/31382531/why-i-cant-create-an-array-with-large-size –

+0

Я не получаю ни одной из этих ошибок –

+0

Ширина и высота целых чисел? Если ширина * высота действительно больше Integer.MAX_VALUE, это означает, что вы не можете удерживать продукт в int. Попытка будет усекать его, поэтому результат в Java всегда будет <= Integer.MAX_VALUE независимо от истинного значения. Один из способов - преобразовать ширину и высоту в тип данных, который всегда может удерживать продукт, например, длинный, до умножения. После этого сравнение с Integer.MAX_VALUE должно работать хорошо. –

ответ

1

BufferedImage предел является тем же пределом, что и byte[Integer.MAX_VALUE] из-за ограничений в классе Raster (ref). У вас также есть накладные расходы на заголовок, который зависит от платформы и реализации. Вот почему я рекомендую буфер безопасности длиной long.

(Integer.MAX_VALUE - 8)/4 должен быть хорошим безопасным пределом.

ПРИМЕЧАНИЕ: вы MUST учтите размер каждого пикселя (ref). Например, BufferedImage.TYPE_4BYTE_ABGR составляет 4 байта на пиксель. Это означает, что в этом случае ваш лимит зоны составляет Integer.MAX_VALUE/4. Конечно, количество байтов, потребляемых каждым пикселем, будет отличаться для используемого вами типа. Настройте максимальную область теста на количество байтов для представления каждого пикселя. Вам нужно будет взглянуть на API, чтобы понять это: https://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html.


Для того, чтобы изменить размер изображения, сохраняя при этом соотношение сторон математика очень проста:

double aspectRatio = width/height; 

if (aspectRatio < 1) { 
    // taller than wide 
    targetHeight = maxDimension; 
    targetWidth = (int)(targetHeight * aspectRatio); 
} else { 
    // wider than tall 
    targetWidth = maxDimension; 
    targetHeight = (int)(targetWidth/aspectRatio); 
} 

Это оставляет вопрос о вычислении maxDimension основаны от общей площади изображения. Для аргумента, допустим, наша максимальная площадь равна Integer.MAX_VALUE - 8 (relatively safe). Мы можем экстраполировать это с помощью алгебры. Мы знаем width * height = area, и с помощью приведенной выше формулы мы имеем два пути, которые нам необходимо решить для нашей максимальной области.

Для aspectRatio < 1 подставим ширина с формулой, чтобы получить его:

height * height * aspectRatio = area

Решение по высоте:

  • height^2 * aspectRatio = area
  • height^2 = area/aspectRatio
  • height = Math.sqrt(area/aspectRatio

Для asptectRatio >= 1 подставим высоту с formulat получить:

width * width/aspectRatio = area

Решение по ширине:

  • шириной^2/AspectRatio = площадь
  • шириной^2 = площадь * AspectRatio
  • width = Math.sqrt (площадь * aspectRatio)

Нет ж мы можем обновить основную формулу для учета формы в максимальной области:

public static final long MAX_AREA = (Integer.MAX_VALUE - 8)/4; 

if (aspectRatio < 1) { 
    targetHeight = Math.sqrt(MAX_AREA/aspectRatio); 
    targetWidth = (int)(targetHeight * aspectRatio); 
} else { 
    // wider than tall 
    targetWidth = Math.sqrt(MAX_AREA * aspectRatio); 
    targetHeight = (int)(targetWidth/aspectRatio); 
} 

Конечно, это оставляет основной вопрос тестирования, если вы выше вашего порога макс области. Это нужно сделать с чем-то иным, чем int.

public static final long MAX_AREA = (Integer.MAX_VALUE - 8)/4; 
long area = (long)width * (long)height; 

if(area < MAX_AREA) { 
    // recalculate size 
} 

В противном случае у вас возникнет проблема с переполнением.

+0

У вас есть те же формулы, что и у меня. –

+0

Добавлены ссылки на соответствующие лимиты и область тестирования. –

+0

Все, что я хочу знать, это ограничение BufferedImage и почему. –