سؤال

لدي مفتوح المصدر التطبيق بتحميل الصور على Facebook.لحفظ عرض النطاق الترددي ، الصور حجمها تلقائيا قبل تحميل (Facebook يفرض حجم أقصى حد).عدد قليل من الناس قد اشتكى من جودة الصورة, و في الواقع يمكنك أن ترى الفرق (انظر هذه المسألة بعض الصور التجريبي).

لذا سؤالي هو: ما هو "أفضل" طريقة تقليص الصور (أيصور) في جافا دون فقدان الجودة ، أو على الأقل ، مع الحد الأدنى من فقدان الجودة / القطع الأثرية ؟

يمكنك أن ترى الرمز الحالي لدي هنا (تغيير رمز عن طريق هذه الصفحة).

هل كانت مفيدة؟

المحلول

ولقد حاولت كل شيء - بما في ذلك الحيل <لأ href = "http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html" يختلط = "noreferrer"> هنا ، وكل ما يمكنني قوله أن كنت أفضل استخدام يماغيماغيك مع أي واجهة والمكتبات التصوير Javas ليست فقط حتى مات عندما يتعلق الأمر بهذا. تحتاج إلى دعم العديد من صيغ والخوارزميات للحصول على ذلك الحق.

نصائح أخرى

فيل, أنا لا أعرف أي الحل الذي ذهب في نهاية المطاف ، ولكن تحجيم الصور في جافا يمكن أن تبدو جيدة جدا إذا كنت:

  • تجنب BufferedImage الأنواع التي ليست مدعومة بشكل جيد من قبل JDK.
  • استخدام تدريجي زيادة
  • التمسك التكعيبي عند استخدام تدريجي زيادة

لقد فعلت حصة عادلة من التجارب مع هذه الأساليب الإضافية القياس جنبا إلى جنب مع إصرارها على دعم أنواع الصور هو مفتاح -- أرى الكسندر المذكورة لا تزال لم تحصل حظا سعيدا مع ذلك مما هو المشكله.

لقد صدر imgscalr المكتبة (أباتشي 2) منذ حوالي 6 أشهر لمعالجة مسألة "أريد حسن المظهر تحجيم نسخ من هذه الصورة ، أن تفعل ذلك الآن!" بعد قراءة شيء مثل 10 أسئلة من هذا القبيل على ذلك.

معيار الاستخدام تبدو مثل:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, 640);

2 الحجة هو إحاطة العرض والارتفاع imgscalr سيتم استخدام مقياس الصورة-حفظ النسب الصحيح حتى لو مرت في غير صالح الأبعاد -- هناك العديد من أكثر طرق مفصلة, ولكن هذا هو أبسط الاستخدام.

استخدام حالة كنت تريد ، على سبيل المثال إذا Facebook محدود من الصور إلى 800 × 600 بكسل ، تبدو مثل هذا:

BufferedImage img = ImageIO.read(...); // load image
BufferedImage scaledImg = Scalr.resize(img, Method.QUALITY, 800, 600);

من شأنها أن تضمن الصورة تبقى في أفضل صورة المدعومة نوع تحجيم مع أعلى جودة الأسلوب الذي جافا يمكن حشده.

في بلدي عالية الدقة الاختبار أنا لم ألحظ أي خطيئة تناقضات مع تحجيم الصور باستخدام هذه المكتبة/هذه الأساليب إلا عندما تصبح صورتك وضعت في سوء دعمت الصورة نوع من ImageIO محمل -- على سبيل المثال ، وهذا يحدث كثيرا مع صور متحركة.إذا تركت لهم مثل ذلك و لا نخرجهم من تلك سيئة دعم أنواع ينتهي تبحث حقا مخلوطة ورهيب.

والسبب في ذلك هو أن Java2D فريق في الواقع مختلف أجهزة تسريع خطوط أنابيب جميع أنواع مختلفة من BufferedImages أن جدك أن عملية - مجموعة فرعية من هذه الأنواع من الصور التي هي أقل شيوعا جميع العودة إلى استخدام نفس البرنامج تقديم خط أنابيب تحت الأغطية في Java2D ، مما أدى إلى ضعف في بعض الأحيان صحيحة تماما تبحث الصور.هذا كان مثل هذا بيا لشرح ومحاولة معرفة أن أنا فقط كتبت هذا المنطق مباشرة إلى المكتبة.

اثنين من أفضل الأنواع المعتمدة هي BufferedImage.TYPE_INT_RGB و _ARGB إذا كنت غريبة.

وهما الأكثر شعبية مفتوحة المصدر يبس متخصصة في تغيير حجم الصورة في جاوة حاليا هي:

الاضافيه هناك جدك الطريقة مع جافا Graphics2D (ترى هذا السؤال حول كيفية القيام بذلك) والتي هي سيئة السمعة إلى إنشاء نتائج سيئة لا سيما مع التقليل.هناك أيضا جافا واجهة ImageMagick والتي سوف يتم حذف هنا لأنه يتطلب خارجي أداة.

الجودة البصرية

هنا هو المقارنة بين نتائج تغيير حجم/نطاق a 580x852 png 145x213.كمرجع فوتوشوب CS5 "حفظ للويب" تغيير حجم استخدامها. ملاحظة:النتائج هي 1:1 ما يبس إنشاء نسخ فقط معا.التكبير لا تستخدم أي تصفية بسيطة فقط أقرب جار الخوارزمية. هنا يمكنك أن تجد الصورة الأصلية.

comparison

  1. Thumbnailator 0.4.8 مع الإعدادات الافتراضية ، لا البعد التعديلات
  2. فوتوشوب CS5 مع التكعيبي الخوارزمية
  3. imgscalr 4.2 مع ULTRA_QUALITY الإعداد ، لا البعد التعديلات
  4. Graphics2D (Java 8) مع تقديم تلميحات VALUE_INTERPOLATION_BICUBIC, VALUE_RENDER_QUALITY, VALUE_ANTIALIAS_ON

أترك القارئ إلى اختيار أفضل نتيجة هذا هو ذاتي.عموما, كل ما يكون جيد الإخراج إلا Graphics2D.Thumbnailator يولد صورا أكثر وضوحا مشابهة جدا فوتوشوب الإخراج ، بينما imgscalr الناتج هو إلى حد كبير أكثر ليونة.بالنسبة الرموز/نص الخ.تريد أكثر وضوحا الناتج عن الصور قد تحتاج أكثر ليونة الإخراج.

الوقت الحسابية

هنا هو غير العلمية المؤشر باستخدام هذا أداة و 114 الصور مع البعد عن من 96x96 حتى 2560x1440 علاج أنها 425% الصور إنشاء:100%, 150%, 200%, 300% و 400% تحجيم إصدارات (هكذا 114 * 5 توسيع نطاق العمليات).كل يبس استخدام نفس الإعدادات كما في الجودة مقارنة (حتى أعلى جودة ممكنة).مرات فقط القياس ليس على العملية برمتها.على i5-2520M مع 8GB من ذاكرة الوصول العشوائي و 5 أشواط.

  • Thumbnailator:7003.0 ms | 6581.3 ms | 6019.1 ms | 6375.3 ms | ms 8700.3
  • imgscalr:25218.5 ms | 25786.6 ms | 25095.7 ms | 25790.4 ms | ms 29296.3
  • Graphics2D:7387.6 ms | 7177.0 ms | 7048.2 ms | 7132.3 ms | ms 7510.3

هنا هو رمز المستخدمة في هذا المعيار.

ومن المثير للاهتمام Thumbnailator هو أيضا أسرع مع متوسط وقت 6.9 ثانية تليها Java2D مع 7.2 ثانية وترك imgscalr خلف مع الفقراء 26.2 ثانية.هذا هو على الارجح ليست عادلة منذ imgscalr هو ULTRA_QUALITY الذي يبدو أن تكون مكلفة للغاية ؛ مع QUALITY وضع المتوسطات في أكثر تنافسية 11.1 ثانية.

لتغيير حجم الصورة مع استخدام نوعية حسب الطلب thumbnailator.jar.

ورمز مثال    http://code.google.com/p/thumbnailator/wiki/Examples

وماذا تلميح تقديم تستخدمه؟ عادة اختزال bicubic سوف يكون أفضل. في الصور التي تربط لأنهم جاجي جدا، مما يجعلني أعتقد أنك تستخدم أقرب جار كما تلميح الخاص بك.

PictureScaler الفئة التي قمت بربط ل، في طريقة paintComponent، ويستخدم ستة وسائل مختلفة لتغيير حجم الصورة. هل حاولت كل ستة لمعرفة أي يعطي أفضل نتيجة؟

بعد بضع محبط التجارب وجدت التالية تغيير حجم التقييم, واستخدمت متعددة تمرير النهج في المشروع.

أن تفعل ذلك أنا نسخ getScaledInstance (طريقة) في مولد المصغرة فئة غيرت صورتي قراءة نهج استخدام ImageIO (أن أحد إرجاع BufferedImage) وأنا الآن سعيدة جدا!

أنا مقارنة النتيجة مع تغيير القيام به في فوتوشوب CS3 و النتيجة هو نفسه كثيرا.

وأردت أعلى مستوى من الجودة تغيير حجم مع نسبة الارتفاع الحفاظ عليها. حاول عدد قليل من الأشياء وقراءة العديد من الإدخالات. فقدت يومين، وفي النهاية حصلت على أفضل نتيجة مع طريقة جافا عادي (كما حاول يماغيماغيك وجافا صورة التحجيم المكتبات):

public static boolean resizeUsingJavaAlgo(String source, File dest, int width, int height) throws IOException {
  BufferedImage sourceImage = ImageIO.read(new FileInputStream(source));
  double ratio = (double) sourceImage.getWidth()/sourceImage.getHeight();
  if (width < 1) {
    width = (int) (height * ratio + 0.4);
  } else if (height < 1) {
    height = (int) (width /ratio + 0.4);
  }

  Image scaled = sourceImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
  BufferedImage bufferedScaled = new BufferedImage(scaled.getWidth(null), scaled.getHeight(null), BufferedImage.TYPE_INT_RGB);
  Graphics2D g2d = bufferedScaled.createGraphics();
  g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
  g2d.drawImage(scaled, 0, 0, width, height, null);
  dest.createNewFile();
  writeJpeg(bufferedScaled, dest.getCanonicalPath(), 1.0f);
  return true;
}


/**
* Write a JPEG file setting the compression quality.
*
* @param image a BufferedImage to be saved
* @param destFile destination file (absolute or relative path)
* @param quality a float between 0 and 1, where 1 means uncompressed.
* @throws IOException in case of problems writing the file
*/
private static void writeJpeg(BufferedImage image, String destFile, float quality)
      throws IOException {
  ImageWriter writer = null;
  FileImageOutputStream output = null;
  try {
    writer = ImageIO.getImageWritersByFormatName("jpeg").next();
    ImageWriteParam param = writer.getDefaultWriteParam();
    param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
    param.setCompressionQuality(quality);
    output = new FileImageOutputStream(new File(destFile));
    writer.setOutput(output);
    IIOImage iioImage = new IIOImage(image, null, null);
    writer.write(null, iioImage, param);
  } catch (IOException ex) {
    throw ex;
  } finally {
    if (writer != null) {
      writer.dispose();
    }
    if (output != null) {
      output.close();
    }
  }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top