2012-01-19 16 views
16

पर कनवर्ट करें, मैं एक एनिमेटेड जीआईएफ इनपुट के रूप में लेना चाहता हूं, फ्रेम (और शायद अन्य मेटाडाटा) गिन सकता हूं, और प्रत्येक को BufferedImage में परिवर्तित कर सकता हूं। मैं यह कैसे कर सकता हूं?प्रत्येक एनिमेटेड जीआईएफ फ्रेम को एक अलग BufferedImage

+0

देखें: http://stackoverflow.com/questions/777947/creating-animated-gif-with-imageio – beerbajay

+1

यह पुस्तकालय भी मदद मिल सकती: https://github.com/dragon66/icafe/wiki – dragon66

उत्तर

10

आप सभी फ्रेम (अनुकूलित GIF के लिए) एक ही आकार के हो कुछ इस तरह की कोशिश करना चाहते हैं:

try { 
    String[] imageatt = new String[]{ 
      "imageLeftPosition", 
      "imageTopPosition", 
      "imageWidth", 
      "imageHeight" 
    };  

    ImageReader reader = (ImageReader)ImageIO.getImageReadersByFormatName("gif").next(); 
    ImageInputStream ciis = ImageIO.createImageInputStream(new File("house2.gif")); 
    reader.setInput(ciis, false); 

    int noi = reader.getNumImages(true); 
    BufferedImage master = null; 

    for (int i = 0; i < noi; i++) { 
     BufferedImage image = reader.read(i); 
     IIOMetadata metadata = reader.getImageMetadata(i); 

     Node tree = metadata.getAsTree("javax_imageio_gif_image_1.0"); 
     NodeList children = tree.getChildNodes(); 

     for (int j = 0; j < children.getLength(); j++) { 
      Node nodeItem = children.item(j); 

      if(nodeItem.getNodeName().equals("ImageDescriptor")){ 
       Map<String, Integer> imageAttr = new HashMap<String, Integer>(); 

       for (int k = 0; k < imageatt.length; k++) { 
        NamedNodeMap attr = nodeItem.getAttributes(); 
        Node attnode = attr.getNamedItem(imageatt[k]); 
        imageAttr.put(imageatt[k], Integer.valueOf(attnode.getNodeValue())); 
       } 
       if(i==0){ 
        master = new BufferedImage(imageAttr.get("imageWidth"), imageAttr.get("imageHeight"), BufferedImage.TYPE_INT_ARGB); 
       } 
       master.getGraphics().drawImage(image, imageAttr.get("imageLeftPosition"), imageAttr.get("imageTopPosition"), null); 
      } 
     } 
     ImageIO.write(master, "GIF", new File(i + ".gif")); 
    } 
} catch (IOException e) { 
    e.printStackTrace(); 
} 
7

ठीक है, मैं कभी नहीं कुछ भी थोड़ा इस तरह से पहले किया है, लेकिन Googling का एक सा और जावा में नगण्य मुझे यह मिल गया:

public ArrayList<BufferedImage> getFrames(File gif) throws IOException{ 
    ArrayList<BufferedImage> frames = new ArrayList<BufferedImage>(); 
    ImageReader ir = new GIFImageReader(new GIFImageReaderSpi()); 
    ir.setInput(ImageIO.createImageInputStream(gif)); 
    for(int i = 0; i < ir.getNumImages(true); i++) 
     frames.add(ir.getRawImageType(i).createBufferedImage(ir.getWidth(i), ir.getHeight(i))); 
    return frames; 
} 

संपादित करें: मेरे जवाब देने के लिए Ansel Zandegran's modification देखते हैं।

2

c24w's solution का उपयोग करना, बदल देते हैं:

साथ
frames.add(ir.getRawImageType(i).createBufferedImage(ir.getWidth(i), ir.getHeight(i))); 

:

frames.add(ir.read(i)); 
8

यहां कोई भी जवाब सही नहीं है और एनीमेशन के लिए उपयुक्त है। प्रत्येक समाधान में कई समस्याएं हैं इसलिए मैंने कुछ लिखा जो वास्तव में सभी gif फ़ाइलों के साथ काम करता है। उदाहरण के लिए, यह पहली फ्रेम की चौड़ाई और ऊंचाई लेने के बजाय छवि की वास्तविक चौड़ाई और ऊंचाई को ध्यान में रखता है, यह मानते हुए कि यह पूरे कैनवास को भर देगा, नहीं, दुर्भाग्य से यह इतना आसान नहीं है। दूसरा, यह कोई पारदर्शी अचार नहीं छोड़ता है। तीसरा, यह खाता निपटान के तरीके को ध्यान में रखता है। चौथा, यह आपको फ्रेम के बीच देरी देता है (* 10 अगर आप इसे थ्रेड.sleep() में उपयोग करना चाहते हैं)।

private ImageFrame[] readGif(InputStream stream) throws IOException{ 
    ArrayList<ImageFrame> frames = new ArrayList<ImageFrame>(2); 

    ImageReader reader = (ImageReader) ImageIO.getImageReadersByFormatName("gif").next(); 
    reader.setInput(ImageIO.createImageInputStream(stream)); 

    int lastx = 0; 
    int lasty = 0; 

    int width = -1; 
    int height = -1; 

    IIOMetadata metadata = reader.getStreamMetadata(); 

    Color backgroundColor = null; 

    if(metadata != null) { 
     IIOMetadataNode globalRoot = (IIOMetadataNode) metadata.getAsTree(metadata.getNativeMetadataFormatName()); 

     NodeList globalColorTable = globalRoot.getElementsByTagName("GlobalColorTable"); 
     NodeList globalScreeDescriptor = globalRoot.getElementsByTagName("LogicalScreenDescriptor"); 

     if (globalScreeDescriptor != null && globalScreeDescriptor.getLength() > 0){ 
      IIOMetadataNode screenDescriptor = (IIOMetadataNode) globalScreeDescriptor.item(0); 

      if (screenDescriptor != null){ 
       width = Integer.parseInt(screenDescriptor.getAttribute("logicalScreenWidth")); 
       height = Integer.parseInt(screenDescriptor.getAttribute("logicalScreenHeight")); 
      } 
     } 

     if (globalColorTable != null && globalColorTable.getLength() > 0){ 
      IIOMetadataNode colorTable = (IIOMetadataNode) globalColorTable.item(0); 

      if (colorTable != null) { 
       String bgIndex = colorTable.getAttribute("backgroundColorIndex"); 

       IIOMetadataNode colorEntry = (IIOMetadataNode) colorTable.getFirstChild(); 
       while (colorEntry != null) { 
        if (colorEntry.getAttribute("index").equals(bgIndex)) { 
         int red = Integer.parseInt(colorEntry.getAttribute("red")); 
         int green = Integer.parseInt(colorEntry.getAttribute("green")); 
         int blue = Integer.parseInt(colorEntry.getAttribute("blue")); 

         backgroundColor = new Color(red, green, blue); 
         break; 
        } 

        colorEntry = (IIOMetadataNode) colorEntry.getNextSibling(); 
       } 
      } 
     } 
    } 

    BufferedImage master = null; 
    boolean hasBackround = false; 

    for (int frameIndex = 0;; frameIndex++) { 
     BufferedImage image; 
     try{ 
      image = reader.read(frameIndex); 
     }catch (IndexOutOfBoundsException io){ 
      break; 
     } 

     if (width == -1 || height == -1){ 
      width = image.getWidth(); 
      height = image.getHeight(); 
     } 

     IIOMetadataNode root = (IIOMetadataNode) reader.getImageMetadata(frameIndex).getAsTree("javax_imageio_gif_image_1.0"); 
     IIOMetadataNode gce = (IIOMetadataNode) root.getElementsByTagName("GraphicControlExtension").item(0); 
     NodeList children = root.getChildNodes(); 

     int delay = Integer.valueOf(gce.getAttribute("delayTime")); 

     String disposal = gce.getAttribute("disposalMethod"); 

     if (master == null){ 
      master = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 
      master.createGraphics().setColor(backgroundColor); 
      master.createGraphics().fillRect(0, 0, master.getWidth(), master.getHeight()); 

     hasBackround = image.getWidth() == width && image.getHeight() == height; 

      master.createGraphics().drawImage(image, 0, 0, null); 
     }else{ 
      int x = 0; 
      int y = 0; 

      for (int nodeIndex = 0; nodeIndex < children.getLength(); nodeIndex++){ 
       Node nodeItem = children.item(nodeIndex); 

       if (nodeItem.getNodeName().equals("ImageDescriptor")){ 
        NamedNodeMap map = nodeItem.getAttributes(); 

        x = Integer.valueOf(map.getNamedItem("imageLeftPosition").getNodeValue()); 
        y = Integer.valueOf(map.getNamedItem("imageTopPosition").getNodeValue()); 
       } 
      } 

      if (disposal.equals("restoreToPrevious")){ 
       BufferedImage from = null; 
       for (int i = frameIndex - 1; i >= 0; i--){ 
        if (!frames.get(i).getDisposal().equals("restoreToPrevious") || frameIndex == 0){ 
         from = frames.get(i).getImage(); 
         break; 
        } 
       } 

       { 
        ColorModel model = from.getColorModel(); 
        boolean alpha = from.isAlphaPremultiplied(); 
        WritableRaster raster = from.copyData(null); 
        master = new BufferedImage(model, raster, alpha, null); 
       } 
      }else if (disposal.equals("restoreToBackgroundColor") && backgroundColor != null){ 
       if (!hasBackround || frameIndex > 1){ 
        master.createGraphics().fillRect(lastx, lasty, frames.get(frameIndex - 1).getWidth(), frames.get(frameIndex - 1).getHeight()); 
       } 
      } 
      master.createGraphics().drawImage(image, x, y, null); 

      lastx = x; 
      lasty = y; 
     } 

     { 
      BufferedImage copy; 

      { 
       ColorModel model = master.getColorModel(); 
       boolean alpha = master.isAlphaPremultiplied(); 
       WritableRaster raster = master.copyData(null); 
       copy = new BufferedImage(model, raster, alpha, null); 
      } 
      frames.add(new ImageFrame(copy, delay, disposal, image.getWidth(), image.getHeight())); 
     } 

     master.flush(); 
    } 
    reader.dispose(); 

    return frames.toArray(new ImageFrame[frames.size()]); 
} 

और ImageFrame वर्ग:

import java.awt.image.BufferedImage; 
public class ImageFrame { 
    private final int delay; 
    private final BufferedImage image; 
    private final String disposal; 
    private final int width, height; 

    public ImageFrame (BufferedImage image, int delay, String disposal, int width, int height){ 
     this.image = image; 
     this.delay = delay; 
     this.disposal = disposal; 
     this.width = width; 
     this.height = height; 
    } 

    public ImageFrame (BufferedImage image){ 
     this.image = image; 
     this.delay = -1; 
     this.disposal = null; 
     this.width = -1; 
     this.height = -1; 
    } 

    public BufferedImage getImage() { 
     return image; 
    } 

    public int getDelay() { 
     return delay; 
    } 

    public String getDisposal() { 
     return disposal; 
    } 

    public int getWidth() { 
     return width; 
    } 

    public int getHeight() { 
      return height; 
    } 
} 
+0

अन्य विधियों ने थोड़ा दूषित उत्पादन किया, यह पूरी तरह से काम किया। – cen

+0

यह कुछ साल पहले वाह से था। वैसे भी, मैंने जावास्क्रिप्ट में एक पूर्ण gif कार्यान्वयन लिखा था। यदि आपको अभी भी समस्याएं हैं तो मैं इसे आपके लिए बंद कर सकता हूं और यह काम करने की गारंटी है। मैंने नोटिस किया कि gifs के लिए ImageReader में निर्मित कभी-कभी वास्तविक पिक्सेल डेटा को डीकोड करने में कुछ समस्याएं होती हैं, फिर भी कुछ लिखने के अलावा इसे ठीक नहीं किया जा सकता है। –

+0

एनिमेटेड जीआईएफ पर आकार बदलने और फसल-टू-फिट लागू करने के लिए मुझे एसओ कोड के कुछ टुकड़े एक साथ स्ट्रिंग करना पड़ा। मैं इसे इस नमूने के साथ पूरी तरह से काम करने के लिए मिला है। सबसे पहले मैंने फ्रांसेस्को द्वारा विधि की कोशिश की लेकिन आउटपुट के पहले कुछ फ्रेमों में कुछ शोर था। अगले कुछ दिनों में मैं अपने समाधान को गिटूब पर फेंक दूंगा अगर कुछ अन्य खो आत्मा कुछ ऐसा करने की कोशिश करती है। जावा और जीआईएफ एक जंगली पश्चिम की तरह हैं। – cen

4

एलेक्स के जवाब ज्यादातर मामलों को शामिल किया गया है, लेकिन यह समस्याओं के एक जोड़े है। यह पारदर्शिता को सही ढंग से संभाल नहीं लेता है (कम से कम आम सम्मेलन के अनुसार) और यह मौजूदा फ्रेम की निपटान विधि को पिछले फ्रेम में लागू कर रहा है जो गलत है। यहाँ एक संस्करण सही ढंग से उन मामलों को संभाल करता है कि है:

private ImageFrame[] readGIF(ImageReader reader) throws IOException { 
    ArrayList<ImageFrame> frames = new ArrayList<ImageFrame>(2); 

    int width = -1; 
    int height = -1; 

    IIOMetadata metadata = reader.getStreamMetadata(); 
    if (metadata != null) { 
     IIOMetadataNode globalRoot = (IIOMetadataNode) metadata.getAsTree(metadata.getNativeMetadataFormatName()); 

     NodeList globalScreenDescriptor = globalRoot.getElementsByTagName("LogicalScreenDescriptor"); 

     if (globalScreenDescriptor != null && globalScreenDescriptor.getLength() > 0) { 
      IIOMetadataNode screenDescriptor = (IIOMetadataNode) globalScreenDescriptor.item(0); 

      if (screenDescriptor != null) { 
       width = Integer.parseInt(screenDescriptor.getAttribute("logicalScreenWidth")); 
       height = Integer.parseInt(screenDescriptor.getAttribute("logicalScreenHeight")); 
      } 
     } 
    } 

    BufferedImage master = null; 
    Graphics2D masterGraphics = null; 

    for (int frameIndex = 0;; frameIndex++) { 
     BufferedImage image; 
     try { 
      image = reader.read(frameIndex); 
     } catch (IndexOutOfBoundsException io) { 
      break; 
     } 

     if (width == -1 || height == -1) { 
      width = image.getWidth(); 
      height = image.getHeight(); 
     } 

     IIOMetadataNode root = (IIOMetadataNode) reader.getImageMetadata(frameIndex).getAsTree("javax_imageio_gif_image_1.0"); 
     IIOMetadataNode gce = (IIOMetadataNode) root.getElementsByTagName("GraphicControlExtension").item(0); 
     int delay = Integer.valueOf(gce.getAttribute("delayTime")); 
     String disposal = gce.getAttribute("disposalMethod"); 

     int x = 0; 
     int y = 0; 

     if (master == null) { 
      master = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 
      masterGraphics = master.createGraphics(); 
      masterGraphics.setBackground(new Color(0, 0, 0, 0)); 
     } else { 
      NodeList children = root.getChildNodes(); 
      for (int nodeIndex = 0; nodeIndex < children.getLength(); nodeIndex++) { 
       Node nodeItem = children.item(nodeIndex); 
       if (nodeItem.getNodeName().equals("ImageDescriptor")) { 
        NamedNodeMap map = nodeItem.getAttributes(); 
        x = Integer.valueOf(map.getNamedItem("imageLeftPosition").getNodeValue()); 
        y = Integer.valueOf(map.getNamedItem("imageTopPosition").getNodeValue()); 
       } 
      } 
     } 
     masterGraphics.drawImage(image, x, y, null); 

     BufferedImage copy = new BufferedImage(master.getColorModel(), master.copyData(null), master.isAlphaPremultiplied(), null); 
     frames.add(new ImageFrame(copy, delay, disposal)); 

     if (disposal.equals("restoreToPrevious")) { 
      BufferedImage from = null; 
      for (int i = frameIndex - 1; i >= 0; i--) { 
       if (!frames.get(i).getDisposal().equals("restoreToPrevious") || frameIndex == 0) { 
        from = frames.get(i).getImage(); 
        break; 
       } 
      } 

      master = new BufferedImage(from.getColorModel(), from.copyData(null), from.isAlphaPremultiplied(), null); 
      masterGraphics = master.createGraphics(); 
      masterGraphics.setBackground(new Color(0, 0, 0, 0)); 
     } else if (disposal.equals("restoreToBackgroundColor")) { 
      masterGraphics.clearRect(x, y, image.getWidth(), image.getHeight()); 
     } 
    } 
    reader.dispose(); 

    return frames.toArray(new ImageFrame[frames.size()]); 
} 

private class ImageFrame { 
    private final int delay; 
    private final BufferedImage image; 
    private final String disposal; 

    public ImageFrame(BufferedImage image, int delay, String disposal) { 
     this.image = image; 
     this.delay = delay; 
     this.disposal = disposal; 
    } 

    public BufferedImage getImage() { 
     return image; 
    } 

    public int getDelay() { 
     return delay; 
    } 

    public String getDisposal() { 
     return disposal; 
    } 
} 

कैसे GIF एनिमेशन this ImageMagick tutorial में काम का अच्छा वर्णन है।

+0

आपको इस कोड में कुछ बदलाव लागू करने की आवश्यकता है। यदि देरी शून्य है तो इसे 100 पर सेट करें, या यदि यह 30ms से कम है, तो इसे 10 से गुणा करें। यह मेरे लिए काम करता है। – Soley

+0

इस दक्षिणी ने मेरे लिए पूरी तरह से काम किया – user3896501

+0

यह एक अन्य लोगों के विपरीत काम करता है, जिसने एक समस्या या किसी अन्य समस्या का सामना किया। –

1

मैंने अपने आप पर एक जीआईएफ छवि डिकोडर लिखा और इसे गिटहब पर अपाचे लाइसेंस 2.0 के तहत जारी किया। आप इसे यहां डाउनलोड कर सकते हैं: https://github.com/DhyanB/Open-Imaging। उदाहरण उपयोग:

void example(final byte[] data) throws Exception { 
    final GifImage gif = GifDecoder .read(data); 
    final int width = gif.getWidth(); 
    final int height = gif.getHeight(); 
    final int background = gif.getBackgroundColor(); 
    final int frameCount = gif.getFrameCount(); 
    for (int i = 0; i < frameCount; i++) { 
     final BufferedImage img = gif.getFrame(i); 
     final int delay = gif.getDelay(i); 
     ImageIO.write(img, "png", new File(OUTPATH + "frame_" + i + ".png")); 
    } 
} 

विकोडक GIF87a, GIF89a, एनीमेशन, पारदर्शिता और इंटरलेसिंग का समर्थन करता है। फ्रेम्स में छवि की चौड़ाई और ऊंचाई होगी और कैनवास पर सही स्थिति पर रखा जाएगा। यह फ्रेम पारदर्शिता और निपटान तरीकों का सम्मान करता है। पृष्ठभूमि रंगों के हैंडलिंग जैसे अधिक विवरण के लिए प्रोजेक्ट विवरण चेकआउट करें।

इसके अतिरिक्त, डिकोडर इस ImageIO बग से पीड़ित नहीं है: ArrayIndexOutOfBoundsException: 4096 while reading gif file

मुझे कुछ प्रतिक्रिया प्राप्त करने में खुशी होगी। मैं छवियों के एक प्रतिनिधि सेट के साथ परीक्षण कर रहा हूं, हालांकि, कुछ वास्तविक क्षेत्र परीक्षण अच्छा होगा।

5

अलग BufferedImage फ्रेम में एक एनिमेटेड GIF विभाजित करने के लिए:

try { 
    ImageReader reader = ImageIO.getImageReadersByFormatName("gif").next(); 
    File input = new File("input.gif"); 
    ImageInputStream stream = ImageIO.createImageInputStream(input); 
    reader.setInput(stream); 

    int count = reader.getNumImages(true); 
    for (int index = 0; index < count; index++) { 
     BufferedImage frame = reader.read(index); 
     // Here you go 
    } 
} catch (IOException ex) { 
    // An I/O problem has occurred 
} 
संबंधित मुद्दे