Changeset 201

Show
Ignore:
Timestamp:
01/16/08 10:00:13 (11 months ago)
Author:
Lutger
Message:

Removed recode, added /examples/recoder. Small changes to Encode. Fixes and additions for editing.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/lodepng/Recode.d

    r43 r201  
    150150    assert(data.length > 0); 
    151151 
    152     ubyte[] dataOut = encode(data, inf, EncodeOptions(cs,fs)); 
     152    ubyte[] dataOut = encode(data, inf); 
    153153    version(Tango) 
    154154    { 
  • trunk/lodepng/dsss.conf

    r158 r201  
    11name=lodepng 
    22[lodepng] 
    3 buildflags = -O -inline -llz 
     3exclude=lodepng/examples 
     4buildflags = -O -inline -version=Tango 
    45version (GNU) { 
    56buildflags += -llz 
  • trunk/lodepng/lodepng/Common.d

    r156 r201  
    103103{ 
    104104    /// constructor 
    105     static PngImage opCall(uint w, uint h, ubyte bd, ColorType ct
     105    static PngImage opCall(uint w, uint h, ubyte bd, ColorType ct, ubyte ilace =0
    106106    { 
    107107        PngImage result; 
     
    113113            colorType = ct; 
    114114            bpp = bitDepth * numChannels(colorType); 
     115            interlaced = ilace;  
    115116        } 
    116117        return result; 
     
    121122    ubyte   bpp; /// bits per pixel 
    122123    ColorType colorType; /// the color format, see also: ColorType 
     124    ubyte interlaced = 0; 
    123125} 
    124126 
     
    387389 
    388390    uint length() { return data.length + 12; } 
    389  
     391     
     392    Chunk dup() 
     393    { 
     394        return Chunk(type, data.dup); 
     395         
     396    } 
    390397    uint type; 
    391398    ubyte[] data; 
     
    733740    return res; 
    734741} 
    735 debug package char[] chunkTypeToString(uint chunkType) 
     742char[] chunkTypeToString(uint chunkType) 
    736743{ 
    737744    char[] result = new char[4]; 
  • trunk/lodepng/lodepng/Decode.d

    r156 r201  
    1818About: 
    1919The decoder is small but sufficient for most purposes. It is compliant to the png specification and 
    20 has been tested with the png suite. The api is procedural and simple, meant to be easily integrated. It is compatible with the 
    21 Phobos and Tango libraries. For Tango, lodepng expects the zlib binding from phobos in etc.c.zlib.d<br> 
     20has been tested with the png suite. To decode images, only <i>decode</i> is needed. The <i>decode32</i> function is for convenience, 
     21it can decode and convert to the common 32-bit RGBA format in one go. 
     22The rest of the api exposes the low-level functionality of lodepng, which is made available in order to use this library 
     23for png-editing purposes. 
     24<br> 
    2225This module publicly imports lodepng.Common, where you'll find the data types used by both the encoder 
    2326and decoder, as well as some utility and image format conversion routines. 
    2427 
    25 Date: August 7, 2007 
     28Date: Januari 16, 2008 
     29 
     30Examples: 
     31Here is an example how you could use LodePNG with opengl, see the api documentation for details. 
     32--- 
     33uint loadPNG(char[] filename) 
     34
     35    uint textureID; 
     36 
     37    glEnable(GL_TEXTURE_2D); 
     38    glGenTextures(1, &textureID); 
     39    glBindTexture(GL_TEXTURE_2D, textureID); 
     40    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); 
     41    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
     42 
     43    PngInfo info; 
     44    ubyte[] image = decode32(cast(ubyte[])std.file.read(filename), info); 
     45 
     46    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, info.image.width, info.image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 
     47                        image.ptr); 
     48    return textureID; 
     49
     50--- 
    2651 
    2752Features: 
     
    4974The following features are not supported. 
    5075<ul> 
    51     <li> editing a PNG image (unless you use the decoder, then edit it, then use the 
    52         encoder, but ignored chunks will then be gone from the original image)</li> 
    5376    <li> Streaming / progressive display. All data must be available and is processed in one call.</li> 
    5477    <li> The following optional chunk types are not interpreted by the decoder 
     
    6689</ul> 
    6790 
    68 Examples: 
    69 Here is an example how you could use LodePNG with opengl, see the api documentation for details. 
    70 --- 
    71 uint loadPNG(char[] filename) 
    72 { 
    73     uint textureID; 
    74  
    75     glEnable(GL_TEXTURE_2D); 
    76     glGenTextures(1, &textureID); 
    77     glBindTexture(GL_TEXTURE_2D, textureID); 
    78     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); 
    79     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
    80  
    81     PngInfo info; 
    82     ubyte[] image = decode32(cast(ubyte[])std.file.read(filename), info); 
    83  
    84     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, info.image.width, info.image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 
    85                         image.ptr); 
    86     return textureID; 
    87 } 
    88 --- 
    8991 
    9092References: 
     
    99101import lodepng.util; 
    100102import std.intrinsic; 
     103version(GNU) 
     104{ 
     105    // handled in dsss.conf 
     106} 
     107else 
     108{ 
     109    pragma(lib, "zlib"); 
     110} 
     111 
     112version (Tango) 
     113{ 
     114    import czlib = tango.io.compress.c.zlib; 
     115} 
     116else 
     117{ 
     118    import czlib = etc.c.zlib; 
     119} 
    101120 
    102121public import lodepng.Common; 
    103122 
     123 
     124/** Decode source png file 
     125 
     126    If a buffer is provided, it may be used to store the result. See bufferSize for details. 
     127 
     128    Throws: PngException 
     129 
     130    Returns: Decoded image pixels. The color format of the resulting image is the 
     131    same as the source image, see lodepng.Common.convert and decode32 if a specific color format 
     132    is desired. 
     133 
     134    Params: 
     135      source = a png file 
     136      info = information about the image will be stored in here 
     137      buffer = optionally provide an array to use as a buffer while decoding 
     138      dg = optionally provide a delegate that will be called for (and only for) unknown chunks 
     139*/ 
     140ubyte[] decode(in ubyte[] source, ref PngInfo info, ubyte[] buffer = null, int delegate(inout Chunk) dg = null) 
     141{ 
     142    info.image = source.readHeader(); 
     143    scope decompressor = new PngDecoder(info.image); 
     144 
     145    foreach(chunk; StreamChunkIter(source[HEADER_SIZE - 1 .. $])) 
     146    { 
     147        if  (chunk.type == IDAT) 
     148            decompressor(chunk.data); 
     149        else if (!parseChunk(chunk, info)) 
     150            if (dg !is null) 
     151                if (dg(chunk) != 0) 
     152                    return null; 
     153 
     154    } 
     155    assert(decompressor.ended); 
     156 
     157    return decompressor.reconstructImage(); 
     158} 
     159 
    104160/*************************************************************************************************** 
    105     Parse png image header from memory. The first 33 bytes of the png file need to be available 
    106  
    107         throws: PngException 
    108  
     161    Decode source png file to 32-bit RGBA format 
     162 
     163    Throws: PngException 
     164 
     165    Returns: decoded image pixels in 32-bit RGBA format 
     166 
     167    Params: 
     168          source = a png file 
     169          info = information about the image will be stored in here 
     170          buffer = optionally provide an array to use as a buffer while decoding 
    109171***************************************************************************************************/ 
    110 PngImage readHeader(in ubyte[] source) 
    111 
    112     ubyte interlace; 
    113     return readHeader(source, interlace); 
    114 
    115  
    116 /// ditto 
    117 PngImage readHeader(in ubyte[] source, out ubyte interlace) 
     172ubyte[] decode32(/+const+/ in ubyte[] source, ref PngInfo info, ubyte[] buffer = null) 
     173
     174    buffer = decode(source, info, buffer); 
     175    buffer = convert(buffer, info, ColorType.RGBA); 
     176    info.image.colorType = ColorType.RGBA; 
     177    info.image.bpp = 32; 
     178    info.image.bitDepth = 8; 
     179    info.palette.length = 0; 
     180    return buffer; 
     181
     182 
     183 
     184/*************************************************************************************************** 
     185    Parse png image header from memory. 
     186 
     187    throws: PngException 
     188 
     189    returns: header information 
     190 
     191    Params: source=must contain the first 33 bytes of a png file 
     192***************************************************************************************************/ 
     193PngImage readHeader(/+const+/ in ubyte[] source) 
    118194in 
    119195{ 
    120     assert(source.length >= HEADER_SIZE, "array is too small to contain png header"); 
     196   assert(source.length >= HEADER_SIZE, "array is too small to contain png header"); 
    121197} 
    122198body // see spec: http://www.w3.org/TR/PNG/#11IHDR 
    123199{ 
    124     mixin(pngEnforce(`source.length >= HEADER_SIZE`, "png header data is too small")); 
    125     mixin(pngEnforce(`source[0..8] == [cast(ubyte)137, 80, 78, 71, 13, 10, 26, 10]`, "invalid png header ")); 
    126     mixin(pngEnforce((toUint(source[12..16]) == IHDR).stringof, "invalid png header")); 
    127     mixin(pngEnforce(`checkCRC(source[29 .. 33], source[12 .. 29])`, "invalid CRC")); 
    128  
    129     PngImage result; 
    130     ubyte interlaceMethod; 
    131  
    132     with (result) 
    133    
    134         width = toUint(source[16..20]); 
    135         height = toUint(source[20..24]); 
    136         bitDepth = source[24]; 
    137         colorType = cast(ColorType)source[25]; 
    138         mixin(pngEnforce( `source[26] == 0`, "unsupported compression method in png header" )); 
    139         mixin(pngEnforce( `source[27] == 0`, "unsupported filter method in png header" )); 
    140         mixin(pngEnforce( `checkColorValidity(colorType, bitDepth)`, "invalid header: wrong color format" )); 
    141         interlaceMethod = source[28]; 
    142         mixin(pngEnforce( `interlaceMethod < 2`, "invalid  interlace method in png header" )); 
    143         bpp = numChannels(colorType) * bitDepth; 
    144    
    145     interlace = interlaceMethod; 
    146     return result; 
     200   mixin(pngEnforce(`source.length >= HEADER_SIZE`, "png header data is too small")); 
     201   mixin(pngEnforce(`source[0..8] == [cast(ubyte)137, 80, 78, 71, 13, 10, 26, 10]`, "invalid png header ")); 
     202   mixin(pngEnforce((toUint(source[12..16]) == IHDR).stringof, "invalid png header")); 
     203   mixin(pngEnforce(`checkCRC(source[29 .. 33], source[12 .. 29])`, "invalid CRC")); 
     204 
     205   PngImage result; 
     206 
     207 
     208   with (result) 
     209   
     210       width = toUint(source[16..20]); 
     211       height = toUint(source[20..24]); 
     212       bitDepth = source[24]; 
     213       colorType = cast(ColorType)source[25]; 
     214       mixin(pngEnforce( `source[26] == 0`, "unsupported compression method in png header" )); 
     215       mixin(pngEnforce( `source[27] == 0`, "unsupported filter method in png header" )); 
     216       mixin(pngEnforce( `checkColorValidity(colorType, bitDepth)`, "invalid header: wrong color format" )); 
     217       interlaced = source[28]; 
     218        mixin(pngEnforce( `interlaced < 2`, "invalid  interlace method in png header" )); 
     219       bpp = numChannels(colorType) * bitDepth; 
     220   
     221 
     222   return result; 
    147223} 
    148224 
    149225/*************************************************************************************************** 
    150     Decode source png file 
    151  
    152         If a buffer is provided, it may be used to store the result. See bufferSize for details. 
    153  
    154         Throws: PngException 
    155         Returns: Decoded image pixels. The color format of the resulting image is the 
    156         same as the source image, see lodepng.Common.convert and decode32 if a specific color format 
    157         is desired. 
     226    Iterates through chunks in source, parses only the header 
     227 
     228    Throws: PngException 
     229    Params: source = a png file 
     230        image = the parsed header 
     231        dg = will be called for each chunk, return anything other than 0 to stop iterating 
    158232 
    159233***************************************************************************************************/ 
    160  
    161 ubyte[] decode(in ubyte[] source, ref PngInfo info, ubyte[] buffer = null, int delegate(inout Chunk) dg = null) 
    162 
    163     info.image = readHeader(source, info.interlace); 
    164  
    165     // holds interlaced filtered scanlines 
    166     ubyte[] ilaceBuffer; 
    167  
    168     // to allocate memory as needed 
    169     if (info.interlace == 1) 
    170         buffer.length = ((info.image.width * info.image.bpp + 7) / 8) * info.image.height + (info.image.height * 2); // guess 
     234void iterateChunks(/+const+/ in ubyte[] source, out PngImage image, int delegate(inout Chunk) dg) 
     235
     236    image = source.readHeader(); 
     237 
     238    foreach(chunk; StreamChunkIter(source[HEADER_SIZE - 1 .. $])) 
     239        if (dg(chunk) != 0) 
     240            return; 
     241
     242 
     243/*************************************************************************************************** 
     244    decode IDAT data 
     245 
     246***************************************************************************************************/ 
     247scope class PngDecoder 
     248
     249    /** constructor */ 
     250    this(PngImage image) 
     251    { 
     252        this(image, buf); 
     253    } 
     254 
     255    /** ditto */ 
     256    this(PngImage image, ref ubyte[] buffer) 
     257    { 
     258        img = image; 
     259        buf = buffer; 
     260        if (img.interlaced == 1) 
     261            buf.length = ((img.width * img.bpp + 7) / 8) * img.height + (img.height * 2); // guess 
     262        else 
     263            buf.length = ((img.width * img.bpp + 7) / 8) * img.height + img.height; 
     264        if (img.interlaced == 1) 
     265            ilaceBuffer.length = buf.length - img.height; 
     266        decoder = DecodeStream.create(buf); 
     267    } 
     268 
     269    /*************************************************************************************************** 
     270        inflate, call multiple times if there are more than 1 IDAT chunks to be decompressed 
     271 
     272        Throws: ZlibException 
     273        params: data of an IDAT chunk 
     274    ***************************************************************************************************/ 
     275    void opCall(ref ubyte[] data) 
     276    { 
     277        decoder(data); 
     278        return true; 
     279    } 
     280 
     281    /*************************************************************************************************** 
     282        Whether inflation has completed 
     283 
     284    ***************************************************************************************************/ 
     285    bool ended() 
     286    { 
     287        return decoder.hasEnded; 
     288    } 
     289 
     290    /*************************************************************************************************** 
     291        Apply reconstruction filters and deinterlace if required 
     292 
     293        note that ended() must return true before this function can be called if no data is provided 
     294 
     295        params: 
     296            filtered=optionally provide uncompressed filtered pixels yourself 
     297    **************************************************************************************************/ 
     298    ubyte[] reconstructImage(ubyte[] filtered = null) 
     299 
     300    { 
     301        buf = filtered is null ? filtered : decoder(); 
     302        return (img.interlaced == 0) ? reconstruct(buf, img) : deinterlace(buf, ilaceBuffer, img); 
     303 
     304    } 
     305 
     306    private 
     307    { 
     308        DecodeStream decoder; 
     309        PngImage img; 
     310 
     311        ubyte[] buf; 
     312        ubyte[] ilaceBuffer; 
     313    } 
     314
     315 
     316 
     317/*************************************************************************************************** 
     318    parse any known chunk except IDAT 
     319 
     320    params: 
     321            chunk=chunk to be parsed 
     322            info=parsed information will be written to info 
     323    returns: true if a chunk is parsed, false otherwise 
     324 
     325***************************************************************************************************/ 
     326bool parseChunk(/+const+/ ref Chunk chunk, ref PngInfo info) 
     327
     328    switch(chunk.type) 
     329    { 
     330        case PLTE: parsePLTE(chunk, info); 
     331            break; 
     332        case tRNS: parsetRNS(chunk, info); 
     333            break; 
     334        case bKGD: parsebKGD(chunk, info); 
     335            break; 
     336        case zTXt: parsezTXt(chunk, info); 
     337            break; 
     338        case tEXt: parsetTXt(chunk, info); 
     339            break; 
     340        case iTXt: parseiTXt(chunk, info); 
     341            break; 
     342        default: 
     343            return false; 
     344    } 
     345    return true; 
     346
     347 
     348/** parse palette chunk */ 
     349void parsePLTE(/+const+/ ref Chunk chunk, ref PngInfo info) 
     350
     351    mixin(pngEnforce(`chunk.data.length <= 256 * 3`, "palette size is too large")); 
     352    info.palette.length = chunk.data.length / 3; 
     353    foreach(index, ref ubyte[4] color; info.palette) 
     354    { 
     355        color[0..3] = chunk.data[index * 3 .. index * 3 + 3]; 
     356        color[3] = 255; 
     357    } 
     358
     359 
     360/** parse transparency chunk */ 
     361void parsetRNS(/+const+/ ref Chunk chunk, ref PngInfo info) 
     362
     363    if (chunk.data.length == 0) 
     364        return; 
     365    info.colorKey = true; 
     366    if (info.image.colorType == ColorType.Palette) // index-values 
     367    { 
     368        mixin(pngEnforce(`chunk.data.length <= info.palette.length`, "palette size is too large")); 
     369        foreach(index, alpha; chunk.data) 
     370            info.palette[index][3] = alpha; 
     371    } 
     372    else if (info.image.colorType == ColorType.RGB) 
     373    { 
     374        info.keyR = 256U * chunk.data[0] + chunk.data[1]; 
     375        info.keyG = 256U * chunk.data[2] + chunk.data[3]; 
     376        info.keyB = 256U * chunk.data[4] + chunk.data[5]; 
     377    } 
     378    else if (info.image.colorType == ColorType.Greyscale) 
     379    { 
     380        info.keyR = 256U * chunk.data[0] + chunk.data[1]; 
     381    } 
    171382    else 
    172         buffer.length = ((info.image.width * info.image.bpp + 7) / 8) * info.image.height + info.image.height; 
    173  
    174  
    175     if (info.interlace == 1) 
    176         ilaceBuffer.length = buffer.length - info.image.height; 
    177  
    178     auto inflator = DecodeStream.create(buffer); 
    179  
    180     foreach(chunk; StreamChunkIter(source[HEADER_SIZE - 1 .. $])) 
    181     { 
    182         switch(chunk.type) 
     383    { 
     384        assert(false); 
     385    } 
     386
     387 
     388/** parse background color chunk */ 
     389void parsebKGD(/+const+/ ref Chunk chunk, ref PngInfo info) 
     390
     391    if (info.image.colorType == ColorType.Palette || info.image.bitDepth == 16) 
     392        info.backgroundColor = chunk.data.dup; 
     393    else 
     394    { 
     395        info.backgroundColor.length = chunk.data.length / 2; 
     396            foreach(index, ref value; info.backgroundColor) 
     397                value = chunk.data[index * 2]; 
     398    } 
     399
     400 
     401/** parse latin1 text chunk */ 
     402void parsetTXt(/+const+/ ref Chunk chunk, ref PngInfo info) 
     403
     404    if (info.parseText) 
     405    { 
     406        auto sep = strFind(cast(char[])chunk.data, 0); 
     407        if (sep > 0) 
     408            info.latin1Text[chunk.data[0..sep]] = chunk.data[sep + 1 .. $]; 
     409    } 
     410
     411 
     412/** parse latin1 compressed text chunk */ 
     413void parsezTXt(/+const+/ ref Chunk chunk, ref PngInfo info) 
     414
     415    if (info.parseText) 
     416    { 
     417        auto sep = strFind(cast(char[])chunk.data, 0); 
     418        if (sep > 0) 
     419        { 
     420            if (chunk.data[sep + 1] == 0) 
     421                info.latin1Text[chunk.data[0..sep]] = chunk.data[sep + 2 .. $]; 
     422            else 
     423            { 
     424                ubyte[] value; 
     425                auto decoder = DecodeStream.create(value); 
     426                decoder(chunk.data[sep + 2 .. $]); 
     427                info.latin1Text[chunk.data[0..sep]] = value; 
     428            } 
     429        } 
     430    } 
     431
     432 
     433/** parse unicode text chunk */ 
     434void parseiTXt(/+const+/ ref Chunk chunk, ref PngInfo info) 
     435
     436    if (info.parseText) 
     437    { 
     438 
     439        auto sep = strFind(cast(char[])chunk.data, 0); 
     440        char[] keyword = cast(char[])chunk.data[0..sep]; 
     441        bool compressed = chunk.data[sep + 1] == 0 ? false : true; 
     442        sep += strFind(cast(char[])chunk.data[sep + 3 .. $], 0) + 3; 
     443        sep += strFind(cast(char[])chunk.data[sep + 1 .. $], 0) + 1; 
     444        if (!compressed) 
     445            info.unicodeText[keyword] = cast(char[])chunk.data[sep + 1..$]; 
     446        else 
    183447        { 
    184             case IDAT: 
    185                 inflator(chunk.data); 
    186                 break; 
    187             case PLTE: 
    188                 mixin(pngEnforce(`chunk.data.length <= 256 * 3`, "palette size is too large")); 
    189                 info.palette.length = chunk.data.length / 3; 
    190                 foreach(index, ref ubyte[4] color; info.palette) 
    191                 { 
    192                     color[0..3] = chunk.data[index * 3 .. index * 3 + 3]; 
    193                     color[3] = 255; 
    194                 } 
    195  
    196                 break; 
    197             case tRNS: 
    198                 if (chunk.data.length == 0) 
    199                     break; 
    200                 info.colorKey = true; 
    201                 if (info.image.colorType == ColorType.Palette) // index-values 
    202                 { 
    203                     mixin(pngEnforce(`chunk.data.length <= info.palette.length`, "palette size is too large")); 
    204                     foreach(index, alpha; chunk.data) 
    205                         info.palette[index][3] = alpha; 
    206                 } 
    207                 else if (info.image.colorType == ColorType.RGB) 
    208                 { 
    209                     info.keyR = 256U * chunk.data[0] + chunk.data[1]; 
    210                     info.keyG = 256U * chunk.data[2] + chunk.data[3]; 
    211                     info.keyB = 256U * chunk.data[4] + chunk.data[5]; 
    212                 } 
    213                 else if (info.image.colorType == ColorType.Greyscale) 
    214                 { 
    215                     info.keyR = 256U * chunk.data[0] + chunk.data[1]; 
    216                 } 
    217                 else 
    218                     assert(false); 
    219                 break; 
    220             case bKGD: 
    221                 if (info.image.colorType == ColorType.Palette || info.image.bitDepth == 16) 
    222                     info.backgroundColor = chunk.data.dup; 
    223                 else 
    224                 { 
    225                     info.backgroundColor.length = chunk.data.length / 2; 
    226                         foreach(index, ref value; info.backgroundColor) 
    227                             value = chunk.data[index * 2]; 
    228                 } 
    229                 break; 
    230             case zTXt: 
    231                 if (info.parseText) 
    232                 { 
    233                     if (info.textual is null) 
    234                         info.textual = new PngText; 
    235                     auto sep = strFind(cast(char[])chunk.data, 0); 
    236                     if (sep > 0) 
    237                     { 
    238                         if (chunk.data[sep + 1] == 0) 
    239                             info.textual[chunk.data[0..sep]] = chunk.data[sep + 2 .. $]; 
    240                         else 
    241                         { 
    242                             ubyte[] value; 
    243                             auto decoder = DecodeStream.create(value); 
    244                             decoder(chunk.data[sep + 2 .. $]); 
    245                             info.textual[chunk.data[0..sep]] = value; 
    246                         } 
    247                     } 
    248                 } 
    249                 break; 
    250             case tEXt: 
    251                 if (info.parseText) 
    252                 { 
    253                     if (info.textual is null) 
    254                         info.textual = new PngText; 
    255                     auto sep = strFind(cast(char[])chunk.data, 0); 
    256                     if (sep > 0) 
    257                     { 
    258                         info.textual[chunk.data[0..sep]] = chunk.data[sep + 1 .. $]; 
    259                     } 
    260                 } 
    261                 break; 
    262             case iTXt: 
    263                 if (info.parseText) 
    264                 { 
    265                     if (info.textual is null) 
    266                         info.textual = new PngText; 
    267                     auto sep = strFind(cast(char[])chunk.data, 0); 
    268                     char[] keyword = cast(char[])chunk.data[0..sep]; 
    269                     bool compressed = chunk.data[sep + 1] == 0 ? false : true; 
    270                     sep += strFind(cast(char[])chunk.data[sep + 3 .. $], 0) + 3; 
    271                     sep += strFind(cast(char[])chunk.data[sep + 1 .. $], 0) + 1; 
    272                     if (!compressed) 
    273                         info.textual[keyword] = cast(char[])chunk.data[sep + 1..$]; 
    274                     else 
    275                     { 
    276                         ubyte[] value; 
    277                         auto decoder = DecodeStream.create(value); 
    278                         decoder(chunk.data[sep + 1..$]); 
    279                         info.textual[keyword] = cast(char[])value; 
    280                     } 
    281                 } 
    282                 break; 
    283             default: 
    284                 if (dg !is null) 
    285                     if (!dg(chunk)) 
    286                         return null; 
    287                 //mixin(pngEnforce(`(bt(&chunk.type, 6) < 0)`, "unrecognized critical chunk")); 
    288                 break; 
     448            ubyte[] value; 
     449            auto decoder = DecodeStream.create(value); 
     450            decoder(chunk.data[sep + 1..$]); 
     451            info.unicodeText[keyword] = cast(char[])value; 
    289452        } 
    290453    } 
    291     assert(inflator.hasEnded); 
    292     buffer = inflator(); 
    293  
    294     return (info.interlace == 0) ? reconstruct(buffer, info.image) 
    295                                  : deinterlace(buffer, ilaceBuffer, info.image); 
    296  
    297 
    298 /+ 
    299 ubyte[] decode(in ubyte[] source, ref PngInfo info, ubyte[] buffer = null) 
    300 
    301     info.image = readHeader(source, info.interlace); 
    302  
    303     // holds interlaced filtered scanlines 
    304     ubyte[] ilaceBuffer; 
    305  
    306     // to allocate memory as needed 
    307     if (info.interlace == 1) 
    308         buffer.length = ((info.image.width * info.image.bpp + 7) / 8) * info.image.height + (info.image.height * 2); // guess 
    309     else 
    310         buffer.length = ((info.image.width * info.image.bpp + 7) / 8) * info.image.height + info.image.height; 
    311  
    312  
    313     if (info.interlace == 1) 
    314         ilaceBuffer.length = buffer.length - info.image.height; 
    315  
    316     auto inflator = DecodeStream.create(buffer); 
    317  
    318     foreach(chunk; StreamChunkIter(source[HEADER_SIZE - 1 .. $])) 
    319     { 
    320         switch(chunk.type) 
    321         { 
    322             case IDAT: 
    323                 inflator(chunk.data); 
    324                 break; 
    325             case PLTE: 
    326                 mixin(pngEnforce(`chunk.data.length <= 256 * 3`, "palette size is too large")); 
    327                 info.palette.length = chunk.data.length / 3; 
    328                 foreach(index, ref ubyte[4] color; info.palette) 
    329                 { 
    330                     color[0..3] = chunk.data[index * 3 .. index * 3 + 3]; 
    331                     color[3] = 255; 
    332                 } 
    333  
    334                 break; 
    335             case tRNS: 
    336                 if (chunk.data.length == 0) 
    337                     break; 
    338                 info.colorKey = true; 
    339                 if (info.image.colorType == ColorType.Palette) // index-values 
    340                 { 
    341                     mixin(pngEnforce(`chunk.data.length <= info.palette.length`, "palette size is too large")); 
    342                     foreach(index, alpha; chunk.data) 
    343                         info.palette[index][3] = alpha; 
    344                 } 
    345                 else if (info.image.colorType == ColorType.RGB) 
    346                 { 
    347                     info.keyR = 256U * chunk.data[0] + chunk.data[1]; 
    348                     info.keyG = 256U * chunk.data[2] + chunk.data[3]; 
    349                     info.keyB = 256U * chunk.data[4] + chunk.data[5]; 
    350                 } 
    351                 else if (info.image.colorType == ColorType.Greyscale) 
    352                 { 
    353                     info.keyR = 256U * chunk.data[0] + chunk.data[1]; 
    354                 } 
    355                 else 
    356                     assert(false); 
    357                 break; 
    358             case bKGD: 
    359                 if (info.image.colorType == ColorType.Palette || info.image.bitDepth == 16) 
    360                     info.backgroundColor = chunk.data.dup; 
    361                 else 
    362                 { 
    363                     info.backgroundColor.length = chunk.data.length / 2; 
    364                         foreach(index, ref value; info.backgroundColor) 
    365                             value = chunk.data[index * 2]; 
    366                 } 
    367                 break; 
    368             case zTXt: 
    369                 if (info.parseText) 
    370                 { 
    371                     if (info.textual is null) 
    372                         info.textual = new PngText; 
    373                     auto sep = strFind(cast(char[])chunk.data, 0); 
    374                     if (sep > 0) 
    375                     { 
    376                         if (chunk.data[sep + 1] == 0) 
    377                             info.textual[chunk.data[0..sep]] = chunk.data[sep + 2 .. $]; 
    378                         else 
    379                         { 
    380                             ubyte[] value; 
    381                             auto decoder = DecodeStream.create(value); 
    382                             decoder(chunk.data[sep + 2 .. $]); 
    383                             info.textual[chunk.data[0..sep]] = value; 
    384                         } 
    385                     } 
    386                 } 
    387                 break; 
    388             case tEXt: 
    389                 if (info.parseText) 
    390                 { 
    391                     if (info.textual is null) 
    392                         info.textual = new PngText; 
    393                     auto sep = strFind(cast(char[])chunk.data, 0); 
    394                     if (sep > 0) 
    395                     { 
    396                         info.textual[chunk.data[0..sep]] = chunk.data[sep + 1 .. $]; 
    397                     } 
    398                 } 
    399                 break; 
    400             case iTXt: 
    401                 if (info.parseText) 
    402                 { 
    403                     if (info.textual is null) 
    404                         info.textual = new PngText; 
    405                     auto sep = strFind(cast(char[])chunk.data, 0); 
    406                     char[] keyword = cast(char[])chunk.data[0..sep]; 
    407                     bool compressed = chunk.data[sep + 1] == 0 ? false : true; 
    408                     sep += strFind(cast(char[])chunk.data[sep + 3 .. $], 0) + 3; 
    409                     sep += strFind(cast(char[])chunk.data[sep + 1 .. $], 0) + 1; 
    410                     if (!compressed) 
    411                         info.textual[keyword] = cast(char[])chunk.data[sep + 1..$]; 
    412                     else 
    413                     { 
    414                         ubyte[] value; 
    415                         auto decoder = DecodeStream.create(value); 
    416                         decoder(chunk.data[sep + 1..$]); 
    417                         info.textual[keyword] = cast(char[])value; 
    418                     } 
    419                 } 
    420                 break; 
    421             default: 
    422                 mixin(pngEnforce(`(bt(&chunk.type, 6) < 0)`, "unrecognized critical chunk")); 
    423                 break; 
    424         } 
    425     } 
    426     assert(inflator.hasEnded); 
    427     buffer = inflator(); 
    428  
    429     return (info.interlace == 0) ? reconstruct(buffer, info.image) 
    430                                  : deinterlace(buffer, ilaceBuffer, info.image); 
    431 
    432 +/ 
    433 /*************************************************************************************************** 
    434     Decode source png file to RGBA format 
    435  
    436         Throws: PngException 
    437         Returns: decoded image pixels in 32-bit RGBA format 
    438 ***************************************************************************************************/ 
    439 ubyte[] decode32(in ubyte[] source, ref PngInfo info, ubyte[] buffer = null) 
    440 
    441     buffer = decode(source, info, buffer); 
    442     buffer = convert(buffer, info, ColorType.RGBA); 
    443     info.image.colorType = ColorType.RGBA; 
    444     info.image.bpp = 32; 
    445     info.image.bitDepth = 8; 
    446     info.palette.length = 0; 
    447     return buffer; 
    448 
     454
     455 
     456 
    449457 
    450458 
  • trunk/lodepng/lodepng/Encode.d

    r157 r201  
    1515  Stewart Gordon (bug fixes) 
    1616 
    17 Date: August 7, 2007 
     17Date: Januari 16, 2008 
    1818 
    1919About: 
    2020The lodepng encoder can encode images of any of the supported png color formats to 24-bit RGB or 
    212132-bit RGBA png images. Conversion, if needed, is done automatically. It is compatible with the 
    22 Phobos and Tango libraries. For Tango, lodepng expects the zlib binding from phobos in etc.c.zlib.d<br> 
     22Phobos and Tango libraries. <br> 
    2323This module publicly imports lodepng.Common, where you'll find the data types used by both the encoder 
    2424and decoder, as well as some utility and image format conversion routines.<br> 
    2525 
    2626Features: 
    27 The following features are supported by the encoder: 
     27The following features are understood by the encoder: 
    2828<ul> 
    29     <li> conformant encoding of 24-bit RGB and 32-bit RGBA PNG images </li> 
    30     <li> automatic conversion of other color formats </li> 
    31     <li> setting the compression and filter methods </li> 
    32     <li> textual key-value metadata: normal and compressed latin1, unicode (utf-8) </li> 
    33     <li> transparency / colorkey </li> 
    34     <li> the following chunks are written by the encoder 
    35         <ul> 
    36             <li>IHDR (image information)</li> 
    37             <li>IDAT (pixel data)</li> 
    38             <li>IEND (the final chunk)</li> 
    39             <li>tRNS (colorkey)</li> 
    40             <li>bKGD (suggested background color) </li> 
    41             <li>tEXt (uncompressed latin-1 key-value strings)</li> 
    42             <li>zTXt (compressed latin-1 key-value strings)</li> 
    43             <li>iTXt (utf8 key-value strings)</li> 
    44         </ul> 
     29    <li> conformant encoding of 24-bit RGB and 32-bit RGBA PNG images </li> 
     30    <li> automatic conversion of other color formats </li> 
     31    <li> setting the compression and filter methods </li> 
     32    <li> textual key-value metadata: normal and compressed latin1, unicode (utf-8) </li> 
     33    <li> transparency / colorkey </li> 
     34    <li> encoding raw chunks </li> 
     35    <li> the following chunks are written by the encoder 
     36        <ul> 
     37            <li>IHDR (image information)</li> 
     38            <li>IDAT (pixel data)</li> 
     39            <li>IEND (the final chunk)</li> 
     40            <li>tRNS (colorkey)</li> 
     41            <li>bKGD (suggested background color) </li> 
     42            <li>tEXt (uncompressed latin-1 key-value strings)</li> 
     43            <li>zTXt (compressed latin-1 key-value strings)</li> 
     44            <li>iTXt (utf8 key-value strings)</li> 
     45        </ul> 
    4546   </li> 
    4647</UL> 
     
    4950The following features are not supported. 
    5051<ul> 
    51    <li> Ouput in any color formats other than 24-bit RGB or 32-bit RGBA</li> 
    52    <li> Interlacing </li> 
    53     <li> The following chunk types are not written by the encoder 
    54        <ul> 
    55            <li>PLTE (color palette)</li> 
    56            <li>cHRM (device independent color info) </li> 
    57            <li>gAMA (device independent color info) </li> 
    58            <li>iCCP (device independent color info) </li> 
    59            <li>sBIT (original number of significant bits) </li> 
    60            <li>sRGB (device independent color info) </li> 
    61            <li>pHYs (physical pixel dimensions) </li> 
    62            <li>sPLT (suggested reduced palette) </li> 
    63            <li>tIME (last image modification time) </li> 
    64        </ul> 
    65    </li> 
     52    <li> Ouput in any color formats other than 24-bit RGB or 32-bit RGBA</li> 
     53    <li> Interlacing </li> 
     54    <li> The encoder does not understand the following chunk types: 
     55        <ul> 
     56            <li>PLTE (color palette)</li> 
     57            <li>cHRM (device independent color info) </li> 
     58            <li>gAMA (device independent color info) </li> 
     59            <li>iCCP (device independent color info) </li> 
     60            <li>sBIT (original number of significant bits) </li> 
     61            <li>sRGB (device independent color info) </li> 
     62            <li>pHYs (physical pixel dimensions) </li> 
     63            <li>sPLT (suggested reduced palette) </li> 
     64            <li>tIME (last image modification time) </li> 
     65        </ul> 
     66    </li> 
    6667</ul> 
    6768 
     
    7677version (Tango) 
    7778{ 
    78    import tango.math.Math; 
     79    import tango.math.Math; 
    7980    import tango.stdc.string; 
    8081} 
    8182else 
    82    import std.math; 
     83    import std.math; 
    8384import lodepng.ZlibCodec; 
    8485public import lodepng.Common; 
    8586 
    8687/*************************************************************************************************** 
    87     Returns a png image of the raw pixels provided by source and described by settings.info 
    88  
    89         This function will attempt to convert to 24-bit RGB if it is a lossless operation, otherwise 
    90         the resulting png image will be in the 32-bit RGBA format. The array returned can be written to disk 
    91         as a png file. 
    92  
    93         throws: PngException 
     88        Encode pixels as a png file 
     89 
     90        This function will attempt to convert to 24-bit RGB if it is a lossless operation, otherwise 
     91        the resulting image will be in the 32-bit RGBA format. The array returned can be written to disk 
     92        as a png file. 
     93 
     94        params: 
     95            source=the pixels to be encoded 
     96            info=description of the source pixels 
     97        throws: PngException 
     98        returns: png file of the raw pixels provided by source and described by settings.info 
    9499***************************************************************************************************/ 
    95100ubyte[] encode(in ubyte[] source, in PngInfo info) 
    96101{ 
    97    ubyte[] buf; 
     102    ubyte[] buf; 
    98103    Chunk[] chunks; 
    99     return _encode(source, Settings(info), buf, chunks); 
    100 
    101  
    102  
     104    return _encode(source, Settings(info), buf, chunks); 
     105
     106 
     107/*************************************************************************************************** 
     108        Encode pixels and / or raw chunks as a png file 
     109 
     110        If chunkList contains IDAT chunks, they must be in order and no source pixels should be provided 
     111 
     112        params: 
     113            source=the pixels to be encoded, can be null 
     114            info=description of the source pixels 
     115            chunkList=array of chunks to be written 
     116        throws: PngException 
     117        returns: png file of the raw pixels provided by source and described by info 
     118***************************************************************************************************/ 
    103119ubyte[] encode(in ubyte[] source, in PngInfo info, ref Chunk[] chunkList) 
    104120{ 
     
    108124 
    109125 
    110 /************************************************************************************************** 
    111     Returns a png image of the raw pixels provided by source and described by settings.info. 
    112  
    113         See also: EncodeOptions 
    114  
    115         throws: PngException 
     126/*************************************************************************************************** 
     127        Encode pixels as a png file 
     128 
     129        see_also: Settings 
     130        params: 
     131            source=the pixels to be encoded 
     132            options=description and options needed to encode the png file 
     133        thro