benjaminpick / java-thumbnailer

An extensible java library to create thumbnails of different file types (image, text)
GNU Lesser General Public License v2.1
47 stars 28 forks source link

AutoCad DWG thumbnail #9

Open rodrigodeppe opened 10 years ago

rodrigodeppe commented 10 years ago

Hello, I've been using this lib for quite a while now. Congratulations on the good job done.

Recently I had to generate thumbs from AutoCad DWG files. I found out that a BMP preview is stored within the file and created a DWGThumbnailer that can be registered on your lib. Thought you would like to have a copy. Of course if you find any room for improvement on the code, feel free to do it. Best regards, Rodrigo Deppe

Here is the code:

public class DWGThumbnailer extends DummyThumbnailer {

public void generateThumbnail(File input, File output) throws IOException, de.uni_siegen.wineme.come_in.thumbnailer.ThumbnailerException {
    //GENERATE FROM EXISTING BITMAP IN DWG
    byte[] outputByte = new byte[4096];
    FileInputStream fis = new FileInputStream(input);
    fis.skip(0x0D);
    fis.read(outputByte, 0, 4);
    int PosSentinel = (((outputByte[3])&0xFF)*256*256*256)+(((outputByte[2])&0xFF)*256*256)+(((outputByte[1])&0xFF)*256)+((outputByte[0])&0xFF);
    fis.skip(PosSentinel-0x0D-4+30);
    outputByte[1]=0;
    fis.read(outputByte, 0, 1);
    int TypePreview = ((outputByte[0])&0xFF);
    if (TypePreview==2) {
        fis.read(outputByte, 0, 4);
        int PosBMP = (((outputByte[3])&0xFF)*256*256*256)+(((outputByte[2])&0xFF)*256*256)+(((outputByte[1])&0xFF)*256)+((outputByte[0])&0xFF);
        fis.read(outputByte, 0, 4);
        int LenBMP = (((outputByte[3])&0xFF)*256*256*256)+(((outputByte[2])&0xFF)*256*256)+(((outputByte[1])&0xFF)*256)+((outputByte[0])&0xFF);
        fis.skip(PosBMP-(PosSentinel+30)-1-4-4+14);
        fis.read(outputByte, 0, 2);
        int biBitCount = (((outputByte[1])&0xFF)*256)+((outputByte[0])&0xFF);
        fis.skip(-16);
        int bisSize=0;
        int bfSize = 0;
        if (biBitCount<9)
            bfSize = 54 + 4 * ((int) (Math.pow(2,biBitCount))) + LenBMP ;
        else bfSize = 54 + LenBMP ;
        //WORD "BM"
        outputByte[0]=0x42;outputByte[1]=0x4D;
        //DWORD bfSize
        outputByte[2]=(byte)(bfSize&0xff);outputByte[3]=(byte)(bfSize>>8&0xff);
        outputByte[4]=(byte)(bfSize>>16&0xff);outputByte[5]=(byte)(bfSize>>>24);
        //WORD bfReserved1
        outputByte[6]=0x00;outputByte[7]=0x00;
        //WORD bfReserved2
        outputByte[8]=0x00;outputByte[9]=0x00;
        //DWORD bfOffBits
        outputByte[10]=0x36;outputByte[11]=0x04;outputByte[12]=0x00;outputByte[13]=0x00;

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos.write(outputByte,0,14);
        while((LenBMP>0) && ((bisSize=fis.read(outputByte, 0, (LenBMP>4096?4096:LenBMP))) != -1)) {
            baos.write(outputByte, 0, bisSize);
            LenBMP-=bisSize;
        }

        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());

        try {
            BufferedImage originalImage = ImageIO.read(bais);
            float scaleWidth = ((float) this.thumbWidth) / originalImage.getWidth();
            float scaleHeight = ((float) this.thumbHeight) / originalImage.getHeight();
            int newWidth = this.thumbWidth;
            int newHeight = this.thumbHeight;
            //PRESERVE ASPECT RATIO
            if (scaleWidth<scaleHeight)
                newHeight=Math.round(newHeight*scaleWidth);
            else newWidth=Math.round(newWidth*scaleHeight);
            BufferedImage newImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
            Graphics g = newImage.createGraphics();
            g.drawImage(originalImage, 0, 0, newWidth, newHeight, null);
            g.dispose();

            ImageIO.write(newImage,"jpg",output);
        } catch (Exception e) {
            //STILL TO DO: support 32bit bitmap rescaling
            bais.reset();
            FileOutputStream fos = new FileOutputStream(output);
            while ((bisSize=bais.read(outputByte, 0, 4096)) != -1) 
                fos.write(outputByte, 0, bisSize);
            fos.close();
        }
    }
    fis.close();
}

public String[] getAcceptedMIMETypes() {
    String dwgMIME = "image/x-dwg" ;
    Collection dwgMIMEColl = new ArrayList();
    dwgMIMEColl.add(dwgMIME) ;
    return (String[]) dwgMIMEColl.toArray(new String[dwgMIMEColl.size()]);
}

}

benjaminpick commented 10 years ago

Hi, nice to hear - thanks for your contribution. I will merge it eventually. Oh, as I don't have AutoCAD: could you create a testfile so that I can include in the testsuite? It doesn't have to fancy, just so that I can see if it breaks.

rodrigodeppe commented 10 years ago

Hi Benjamin,

I’ve updated the code on github since I noticed that the rescaling of 32bit bmp files was not working. Maybe you can take a look at this.

It seems like the AutoCad DWG file can have an 8, 24 or 32 bit bitmap embebed on it.

Attached are some samples. The visualization - aerial.dwg I have downloaded from the AutoCad website.

Rodrigo Deppe

De: Benjamin Pick [mailto:notifications@github.com] Enviada em: domingo, 10 de agosto de 2014 12:50 Para: benjaminpick/java-thumbnailer Cc: Rodrigo Deppe Assunto: Re: [java-thumbnailer] AutoCad DWG thumbnail (#9)

Hi, nice to hear - thanks for your contribution. I will merge it eventually. Oh, as I don't have AutoCAD: could you create a testfile so that I can include in the testsuite? It doesn't have to fancy, just so that I can see if it breaks.

— Reply to this email directly or view it on GitHub https://github.com/benjaminpick/java-thumbnailer/issues/9#issuecomment-51718553 .Imagem removida pelo remetente.

benjaminpick commented 10 years ago

Hi Rodrigo,

so I've merged your thumbnailer and replaced the scaling code by my Util Class (so that the resulting image always has the specified size).

32bit, however, still doesn't work:

[junit] Caused by: java.io.EOFException [junit] at javax.imageio.stream.ImageInputStreamImpl.readFully(ImageInputStreamImpl.java:353) [junit] at javax.imageio.stream.ImageInputStreamImpl.readFully(ImageInputStreamImpl.java:405) [junit] at com.sun.imageio.plugins.bmp.BMPImageReader.read32Bit(BMPImageReader.java:1353) [junit] at com.sun.imageio.plugins.bmp.BMPImageReader.read(BMPImageReader.java:890) [junit] at javax.imageio.ImageIO.read(ImageIO.java:1448) [junit] at javax.imageio.ImageIO.read(ImageIO.java:1352)

Note that Java recognizes it as 32bit, but cannot read enough bytes. My guess is that one of the magical numbers in the code above need to be updated, but as I don't know the spec of BMP I have to desire to start debugging :-)

Where is the code coming from, actually? Did you write it or get it from an GPL-licenced project?

rodrigodeppe commented 10 years ago

Hey, Benjamin.

Funny. If you let the 32bmp get extracted to disk you will see that MS Paint and other programs are able to read it. Even explorer, on its thumbnail setting, can show it. I will take a look at the BMP specs to see if I missed anything. It sure looks like it wanted to read more.

About the code, I got it from the specs on the file attached (pages 22, 88 & 89). The BMP specs for creating the header I found in some pages over the internet.

I will let you know if I find out anything or not.

Thanks,

Rodrigo Deppe

De: Benjamin Pick [mailto:notifications@github.com] Enviada em: sábado, 16 de agosto de 2014 05:20 Para: benjaminpick/java-thumbnailer Cc: Rodrigo Deppe Assunto: Re: [java-thumbnailer] AutoCad DWG thumbnail (#9)

Hi Rodrigo,

so I've merged your thumbnailer and replaced the scaling code by my Util Class (so that the resulting image always has the specified size).

32bit, however, still doesn't work:

[junit] Caused by: java.io.EOFException [junit] at javax.imageio.stream.ImageInputStreamImpl.readFully(ImageInputStreamImpl.java:353) [junit] at javax.imageio.stream.ImageInputStreamImpl.readFully(ImageInputStreamImpl.java:405) [junit] at com.sun.imageio.plugins.bmp.BMPImageReader.read32Bit(BMPImageReader.java:1353) [junit] at com.sun.imageio.plugins.bmp.BMPImageReader.read(BMPImageReader.java:890) [junit] at javax.imageio.ImageIO.read(ImageIO.java:1448) [junit] at javax.imageio.ImageIO.read(ImageIO.java:1352)

Note that Java recognizes it as 32bit, but cannot read enough bytes. My guess is that one of the magical numbers in the code above need to be updated, but as I don't know the spec of BMP I have to desire to start debugging :-)

Where is the code coming from, actually? Did you write it or get it from an GPL-licenced project?

— Reply to this email directly or view it on GitHub https://github.com/benjaminpick/java-thumbnailer/issues/9#issuecomment-52387298 . https://github.com/notifications/beacon/8402283__eyJzY29wZSI6Ik5ld3NpZXM6QmVhY29uIiwiZXhwaXJlcyI6MTcyMzc5NjQwOCwiZGF0YSI6eyJpZCI6MzkyNTkxMjh9fQ==--c8e889f6ee0662d1805ccbdde884abf4f9bc947b.gif