Exemple #1
1
        /// <summary>
        /// Gets the filter specified by the case sensitive name.
        /// </summary>
        public static Filter GetFilter(string filterName)
        {
            if (filterName.StartsWith("/"))
            {
                filterName = filterName.Substring(1);
            }

            // Some tools use abbreviations
            switch (filterName)
            {
            case "ASCIIHexDecode":
            case "AHx":
                return(_asciiHexDecode ?? (_asciiHexDecode = new AsciiHexDecode()));

            case "ASCII85Decode":
            case "A85":
                return(_ascii85Decode ?? (_ascii85Decode = new Ascii85Decode()));

            case "LZWDecode":
            case "LZW":
                return(_lzwDecode ?? (_lzwDecode = new LzwDecode()));

            case "FlateDecode":
            case "Fl":
                return(_flateDecode ?? (_flateDecode = new FlateDecode()));

            //case "RunLengthDecode":
            //  if (RunLengthDecode == null)
            //    RunLengthDecode = new RunLengthDecode();
            //  return RunLengthDecode;
            //
            //case "CCITTFaxDecode":
            //  if (CCITTFaxDecode == null)
            //    CCITTFaxDecode = new CCITTFaxDecode();
            //  return CCITTFaxDecode;
            //
            //case "JBIG2Decode":
            //  if (JBIG2Decode == null)
            //    JBIG2Decode = new JBIG2Decode();
            //  return JBIG2Decode;
            //
            //case "DCTDecode":
            //  if (DCTDecode == null)
            //    DCTDecode = new DCTDecode();
            //  return DCTDecode;
            //
            //case "JPXDecode":
            //  if (JPXDecode == null)
            //    JPXDecode = new JPXDecode();
            //  return JPXDecode;
            //
            //case "Crypt":
            //  if (Crypt == null)
            //    Crypt = new Crypt();
            //  return Crypt;

            case "RunLengthDecode":
            case "CCITTFaxDecode":
            case "JBIG2Decode":
            case "DCTDecode":
            case "JPXDecode":
            case "Crypt":
                Debug.WriteLine("Filter not implemented: " + filterName);
                return(null);
            }
            throw new NotImplementedException("Unknown filter: " + filterName);
        }
    private static PdfDictionary ProcessFilters(PdfDictionary dictionary)
    {
      PdfDictionary result;

      // Create a dictionary mapping (i.e. switch statement) to process the expected filters.
      var map = new Dictionary<string, Func<byte[], byte[]>>() {
        { "/FlateDecode", (d) => {
          var decoder = new FlateDecode();
          return (decoder.Decode(d));
        } }
      };

      // Get all of the filters.
      var filters = ((PdfArray)dictionary.Elements["/Filter"])
                                         .Elements.Where(e => e.IsName())
                                         .Select(e => ((PdfName)e).Value)
                                         .ToList();
      // If only one filter in array. Just rewrite the /Filter
      if (filters.Count == 1) {
        result = dictionary.Clone();
        result.Elements["/Filter"] = new PdfName(filters[0]);
        return (result);
      }
      
      // Process each filter in order. The last filter should be the actual encoded image.
      byte[] data = dictionary.Stream.Value;
      for(int index = 0; index < (filters.Count - 1); index++) {
        if (! map.ContainsKey(filters[index])) {
          throw new NotSupportedException(String.Format("Encountered embedded image with multiple filters: \"{0}\". Unable to process the filter: \"{1}\".",
                                                        String.Join(",", filters), filters[index]));
        }
        data = map[filters[index]].Invoke(data);
      }

      result = new PdfDictionary();
      result.Elements.Add("/Filter", new PdfName(filters.Last()));
      foreach (var element in dictionary.Elements.Where(e => !String.Equals(e.Key, "/Filter", StringComparison.OrdinalIgnoreCase))) {
        result.Elements.Add(element.Key, element.Value);
      }
      result.CreateStream(data);

      return(result);
    }
Exemple #3
0
    /// <summary>
    /// Reads images that are returned from GDI+ without color palette.
    /// </summary>
    /// <param name="components">4 (32bpp RGB), 3 (24bpp RGB, 32bpp ARGB)</param>
    /// <param name="bits">8</param>
    /// <param name="hasAlpha">true (ARGB), false (RGB)</param>
    private void ReadTrueColorMemoryBitmap(int components, int bits, bool hasAlpha)
    {
#if DEBUG_
      image.image.Save("$$$.bmp", ImageFormat.Bmp);
#endif
      int pdfVersion = Owner.Version;
      MemoryStream memory = new MemoryStream();
#if GDI
      image.gdiImage.Save(memory, ImageFormat.Bmp);
#endif
#if WPF
#if !SILVERLIGHT
      // WPFTHHO: Bitte prüfen
      BmpBitmapEncoder encoder = new BmpBitmapEncoder();
      encoder.Frames.Add(BitmapFrame.Create(image.wpfImage));
      encoder.Save(memory);
#else
      // AGHACK
#endif
#endif
      int streamLength = (int)memory.Length;
      Debug.Assert(streamLength > 0, "Bitmap image encoding failed.");
      if (streamLength > 0)
      {
        byte[] imageBits = new byte[streamLength];
        memory.Seek(0, SeekOrigin.Begin);
        memory.Read(imageBits, 0, streamLength);
        memory.Close();

        int height = image.PixelHeight;
        int width = image.PixelWidth;

        // TODO: we could define structures for
        //   BITMAPFILEHEADER
        //   { BITMAPINFO }
        //   BITMAPINFOHEADER
        // to avoid ReadWord and ReadDWord ... (but w/o pointers this doesn't help much)

        if (ReadWord(imageBits, 0) != 0x4d42 || // "BM"
            ReadDWord(imageBits, 2) != streamLength ||
            ReadDWord(imageBits, 14) != 40 || // sizeof BITMAPINFOHEADER
            ReadDWord(imageBits, 18) != width ||
            ReadDWord(imageBits, 22) != height)
        {
          throw new NotImplementedException("ReadTrueColorMemoryBitmap: unsupported format");
        }
        if (ReadWord(imageBits, 26) != 1 ||
          (!hasAlpha && ReadWord(imageBits, 28) != components * bits ||
           hasAlpha && ReadWord(imageBits, 28) != (components + 1) * bits) ||
          ReadDWord(imageBits, 30) != 0)
        {
          throw new NotImplementedException("ReadTrueColorMemoryBitmap: unsupported format #2");
        }

        int nFileOffset = ReadDWord(imageBits, 10);
        int logicalComponents = components;
        if (components == 4)
          logicalComponents = 3;

        byte[] imageData = new byte[components * width * height];

        bool hasMask = false;
        bool hasAlphaMask = false;
        byte[] alphaMask = hasAlpha ? new byte[width * height] : null;
        MonochromeMask mask = hasAlpha ?
          new MonochromeMask(width, height) : null;

        int nOffsetRead = 0;
        if (logicalComponents == 3)
        {
          for (int y = 0; y < height; ++y)
          {
            int nOffsetWrite = 3 * (height - 1 - y) * width;
            int nOffsetWriteAlpha = 0;
            if (hasAlpha)
            {
              mask.StartLine(y);
              nOffsetWriteAlpha = (height - 1 - y) * width;
            }

            for (int x = 0; x < width; ++x)
            {
              imageData[nOffsetWrite] = imageBits[nFileOffset + nOffsetRead + 2];
              imageData[nOffsetWrite + 1] = imageBits[nFileOffset + nOffsetRead + 1];
              imageData[nOffsetWrite + 2] = imageBits[nFileOffset + nOffsetRead];
              if (hasAlpha)
              {
                mask.AddPel(imageBits[nFileOffset + nOffsetRead + 3]);
                alphaMask[nOffsetWriteAlpha] = imageBits[nFileOffset + nOffsetRead + 3];
                if (!hasMask || !hasAlphaMask)
                {
                  if (imageBits[nFileOffset + nOffsetRead + 3] != 255)
                  {
                    hasMask = true;
                    if (imageBits[nFileOffset + nOffsetRead + 3] != 0)
                      hasAlphaMask = true;
                  }
                }
                ++nOffsetWriteAlpha;
              }
              nOffsetRead += hasAlpha ? 4 : components;
              nOffsetWrite += 3;
            }
            nOffsetRead = 4 * ((nOffsetRead + 3) / 4); // Align to 32 bit boundary
          }
        }
        else if (components == 1)
        {
          // Grayscale
          throw new NotImplementedException("Image format not supported (grayscales).");
        }

        FlateDecode fd = new FlateDecode();
        if (hasMask)
        {
          // monochrome mask is either sufficient or
          // provided for compatibility with older reader versions
          byte[] maskDataCompressed = fd.Encode(mask.MaskData);
          PdfDictionary pdfMask = new PdfDictionary(document);
          pdfMask.Elements.SetName(Keys.Type, "/XObject");
          pdfMask.Elements.SetName(Keys.Subtype, "/Image");

          Owner.irefTable.Add(pdfMask);
          pdfMask.Stream = new PdfStream(maskDataCompressed, pdfMask);
          pdfMask.Elements[Keys.Length] = new PdfInteger(maskDataCompressed.Length);
          pdfMask.Elements[Keys.Filter] = new PdfName("/FlateDecode");
          pdfMask.Elements[Keys.Width] = new PdfInteger(width);
          pdfMask.Elements[Keys.Height] = new PdfInteger(height);
          pdfMask.Elements[Keys.BitsPerComponent] = new PdfInteger(1);
          pdfMask.Elements[Keys.ImageMask] = new PdfBoolean(true);
          Elements[Keys.Mask] = pdfMask.Reference;
        }
        if (hasMask && hasAlphaMask && pdfVersion >= 14)
        {
          // The image provides an alpha mask (requires Arcrobat 5.0 or higher)
          byte[] alphaMaskCompressed = fd.Encode(alphaMask);
          PdfDictionary smask = new PdfDictionary(document);
          smask.Elements.SetName(Keys.Type, "/XObject");
          smask.Elements.SetName(Keys.Subtype, "/Image");

          Owner.irefTable.Add(smask);
          smask.Stream = new PdfStream(alphaMaskCompressed, smask);
          smask.Elements[Keys.Length] = new PdfInteger(alphaMaskCompressed.Length);
          smask.Elements[Keys.Filter] = new PdfName("/FlateDecode");
          smask.Elements[Keys.Width] = new PdfInteger(width);
          smask.Elements[Keys.Height] = new PdfInteger(height);
          smask.Elements[Keys.BitsPerComponent] = new PdfInteger(8);
          smask.Elements[Keys.ColorSpace] = new PdfName("/DeviceGray");
          Elements[Keys.SMask] = smask.Reference;
        }

        byte[] imageDataCompressed = fd.Encode(imageData);

        Stream = new PdfStream(imageDataCompressed, this);
        Elements[Keys.Length] = new PdfInteger(imageDataCompressed.Length);
        Elements[Keys.Filter] = new PdfName("/FlateDecode");
        Elements[Keys.Width] = new PdfInteger(width);
        Elements[Keys.Height] = new PdfInteger(height);
        Elements[Keys.BitsPerComponent] = new PdfInteger(8);
        // TODO: CMYK
        Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB");
        if (image.Interpolate)
          Elements[Keys.Interpolate] = PdfBoolean.True;
      }
    }
Exemple #4
0
    /* BITMAPINFOHEADER struct and byte offsets:
        typedef struct tagBITMAPINFOHEADER{
          DWORD  biSize;           // 14
          LONG   biWidth;          // 18
          LONG   biHeight;         // 22
          WORD   biPlanes;         // 26
          WORD   biBitCount;       // 28
          DWORD  biCompression;    // 30
          DWORD  biSizeImage;      // 34
          LONG   biXPelsPerMeter;  // 38
          LONG   biYPelsPerMeter;  // 42
          DWORD  biClrUsed;        // 46
          DWORD  biClrImportant;   // 50
        } BITMAPINFOHEADER, *PBITMAPINFOHEADER; 
    */

    private void ReadIndexedMemoryBitmap(int bits/*, ref bool hasAlpha*/)
    {
#if DEBUG_
      image.image.Save("$$$.bmp", ImageFormat.Bmp);
#endif
      int pdfVersion = Owner.Version;
      int firstMaskColor = -1, lastMaskColor = -1;
      bool segmentedColorMask = false;

      MemoryStream memory = new MemoryStream();
#if GDI
      image.gdiImage.Save(memory, ImageFormat.Bmp);
#endif
#if WPF
#if !SILVERLIGHT
      // WPFTHHO: StL: keine Ahnung ob das so stimmt.
      BmpBitmapEncoder encoder = new BmpBitmapEncoder();
      encoder.Frames.Add(BitmapFrame.Create(image.wpfImage));
      encoder.Save(memory);
#else
      // AGHACK
#endif
#endif
      int streamLength = (int)memory.Length;
      Debug.Assert(streamLength > 0, "Bitmap image encoding failed.");
      if (streamLength > 0)
      {
        byte[] imageBits = new byte[streamLength];
        memory.Seek(0, SeekOrigin.Begin);
        memory.Read(imageBits, 0, streamLength);
        memory.Close();

        int height = image.PixelHeight;
        int width = image.PixelWidth;

        if (ReadWord(imageBits, 0) != 0x4d42 || // "BM"
          ReadDWord(imageBits, 2) != streamLength ||
          ReadDWord(imageBits, 14) != 40 || // sizeof BITMAPINFOHEADER
#if WPF
          // TODOWPF: bug with height and width??? With which files???
          ReadDWord(imageBits, 18) != width ||
          ReadDWord(imageBits, 22) != height)
#else
          ReadDWord(imageBits, 18) != width ||
          ReadDWord(imageBits, 22) != height)
#endif
        {
          throw new NotImplementedException("ReadIndexedMemoryBitmap: unsupported format");
        }
#if WPF
        // TODOWPF: bug with height and width
        width = ReadDWord(imageBits, 18);
        height = ReadDWord(imageBits, 22);
#endif
        int fileBits = ReadWord(imageBits, 28);
        if (fileBits != bits)
        {
          if (fileBits == 1 || fileBits == 4 || fileBits == 8)
            bits = fileBits;
        }

        if (ReadWord(imageBits, 26) != 1 ||
            ReadWord(imageBits, 28) != bits ||
            ReadDWord(imageBits, 30) != 0)
        {
          throw new NotImplementedException("ReadIndexedMemoryBitmap: unsupported format #2");
        }

        int bytesFileOffset = ReadDWord(imageBits, 10);
        int bytesColorPaletteOffset = 0x36; // GDI+ always returns Windows bitmaps: sizeof BITMAPFILEHEADER + sizeof BITMAPINFOHEADER
        int paletteColors = ReadDWord(imageBits, 46);
        if ((bytesFileOffset - bytesColorPaletteOffset) / 4 != paletteColors)
        {
          throw new NotImplementedException("ReadIndexedMemoryBitmap: unsupported format #3");
        }

        MonochromeMask mask = new MonochromeMask(width, height);

        bool isGray = bits == 8 && (paletteColors == 256 || paletteColors == 0);
        int isBitonal = 0; // 0: false; >0: true; <0: true (inverted)
        byte[] paletteData = new byte[3 * paletteColors];
        for (int color = 0; color < paletteColors; ++color)
        {
          paletteData[3 * color] = imageBits[bytesColorPaletteOffset + 4 * color + 2];
          paletteData[3 * color + 1] = imageBits[bytesColorPaletteOffset + 4 * color + 1];
          paletteData[3 * color + 2] = imageBits[bytesColorPaletteOffset + 4 * color + 0];
          if (isGray)
            isGray = paletteData[3 * color] == paletteData[3 * color + 1] &&
              paletteData[3 * color] == paletteData[3 * color + 2];

          if (imageBits[bytesColorPaletteOffset + 4 * color + 3] < 128)
          {
            // We treat this as transparency:
            if (firstMaskColor == -1)
              firstMaskColor = color;
            if (lastMaskColor == -1 || lastMaskColor == color - 1)
              lastMaskColor = color;
            if (lastMaskColor != color)
              segmentedColorMask = true;
          }
          //else
          //{
          //  // We treat this as opacity:
          //}
        }

        if (bits == 1)
        {
          if (paletteColors == 0)
            isBitonal = 1;
          if (paletteColors == 2)
          {
            if (paletteData[0] == 0 &&
              paletteData[1] == 0 &&
              paletteData[2] == 0 &&
              paletteData[3] == 255 &&
              paletteData[4] == 255 &&
              paletteData[5] == 255)
              isBitonal = 1; // Black on white
            if (paletteData[5] == 0 &&
              paletteData[4] == 0 &&
              paletteData[3] == 0 &&
              paletteData[2] == 255 &&
              paletteData[1] == 255 &&
              paletteData[0] == 255)
              isBitonal = -1; // White on black
          }
        }

        // NYI: (no sample found where this was required) 
        // if (segmentedColorMask = true)
        // { ... }

        FlateDecode fd = new FlateDecode();
        PdfDictionary colorPalette = null;
        if (isBitonal == 0 && !isGray)
        {
          colorPalette = new PdfDictionary(this.document);
          byte[] packedPaletteData = paletteData.Length >= 48 ? fd.Encode(paletteData) : null; // don't compress small palettes
          if (packedPaletteData != null && packedPaletteData.Length + 20 < paletteData.Length) // +20: compensate for the overhead (estimated value)
          {
            // Create compressed color palette:
            colorPalette.CreateStream(packedPaletteData);
            colorPalette.Elements[Keys.Length] = new PdfInteger(packedPaletteData.Length);
            colorPalette.Elements[Keys.Filter] = new PdfName("/FlateDecode");
          }
          else
          {
            // Create uncompressed color palette:
            colorPalette.CreateStream(paletteData);
            colorPalette.Elements[Keys.Length] = new PdfInteger(paletteData.Length);
          }
          Owner.irefTable.Add(colorPalette);
        }

        bool isFaxEncoding = false;
        byte[] imageData = new byte[((width * bits + 7) / 8) * height];
        byte[] imageDataFax = null;
        int k = 0;


        if (bits == 1)
        {
          // TODO: flag/option?
          // We try Group 3 1D and Group 4 (2D) encoding here and keep the smaller byte array.
          //byte[] temp = new byte[imageData.Length];
          //int ccittSize = DoFaxEncoding(ref temp, imageBits, (uint)bytesFileOffset, (uint)width, (uint)height);

          // It seems that Group 3 2D encoding never beats both other encodings, therefore we don't call it here.
          //byte[] temp2D = new byte[imageData.Length];
          //uint dpiY = (uint)image.VerticalResolution;
          //uint kTmp = 0;
          //int ccittSize2D = DoFaxEncoding2D((uint)bytesFileOffset, ref temp2D, imageBits, (uint)width, (uint)height, dpiY, out kTmp);
          //k = (int) kTmp;

          byte[] tempG4 = new byte[imageData.Length];
          int ccittSizeG4 = DoFaxEncodingGroup4(ref tempG4, imageBits, (uint)bytesFileOffset, (uint)width, (uint)height);

          isFaxEncoding = /*ccittSize > 0 ||*/ ccittSizeG4 > 0;
          if (isFaxEncoding)
          {
            //if (ccittSize == 0)
            //  ccittSize = 0x7fffffff;
            if (ccittSizeG4 == 0)
              ccittSizeG4 = 0x7fffffff;
            //if (ccittSize <= ccittSizeG4)
            //{
            //  Array.Resize(ref temp, ccittSize);
            //  imageDataFax = temp;
            //  k = 0;
            //}
            //else
            {
              Array.Resize(ref tempG4, ccittSizeG4);
              imageDataFax = tempG4;
              k = -1;
            }
          }
        }

        //if (!isFaxEncoding)
        {
          int bytesOffsetRead = 0;
          if (bits == 8 || bits == 4 || bits == 1)
          {
            int bytesPerLine = (width * bits + 7) / 8;
            for (int y = 0; y < height; ++y)
            {
              mask.StartLine(y);
              int bytesOffsetWrite = (height - 1 - y) * ((width * bits + 7) / 8);
              for (int x = 0; x < bytesPerLine; ++x)
              {
                if (isGray)
                {
                  // Lookup the gray value from the palette:
                  imageData[bytesOffsetWrite] = paletteData[3 * imageBits[bytesFileOffset + bytesOffsetRead]];
                }
                else
                {
                  // Store the palette index:
                  imageData[bytesOffsetWrite] = imageBits[bytesFileOffset + bytesOffsetRead];
                }
                if (firstMaskColor != -1)
                {
                  int n = imageBits[bytesFileOffset + bytesOffsetRead];
                  if (bits == 8)
                  {
                    // TODO???: segmentedColorMask == true => bad mask NYI
                    mask.AddPel((n >= firstMaskColor) && (n <= lastMaskColor));
                  }
                  else if (bits == 4)
                  {
                    // TODO???: segmentedColorMask == true => bad mask NYI
                    int n1 = (n & 0xf0) / 16;
                    int n2 = (n & 0x0f);
                    mask.AddPel((n1 >= firstMaskColor) && (n1 <= lastMaskColor));
                    mask.AddPel((n2 >= firstMaskColor) && (n2 <= lastMaskColor));
                  }
                  else if (bits == 1)
                  {
                    // TODO???: segmentedColorMask == true => bad mask NYI
                    for (int bit = 1; bit <= 8; ++bit)
                    {
                      int n1 = (n & 0x80) / 128;
                      mask.AddPel((n1 >= firstMaskColor) && (n1 <= lastMaskColor));
                      n *= 2;
                    }
                  }
                }
                bytesOffsetRead += 1;
                bytesOffsetWrite += 1;
              }
              bytesOffsetRead = 4 * ((bytesOffsetRead + 3) / 4); // Align to 32 bit boundary
            }
          }
          else
          {
            throw new NotImplementedException("ReadIndexedMemoryBitmap: unsupported format #3");
          }
        }

        if (firstMaskColor != -1 &&
          lastMaskColor != -1)
        {
          // Color mask requires Reader 4.0 or higher:
          if (!segmentedColorMask && pdfVersion >= 13)
          {
            PdfArray array = new PdfArray(document);
            array.Elements.Add(new PdfInteger(firstMaskColor));
            array.Elements.Add(new PdfInteger(lastMaskColor));
            Elements[Keys.Mask] = array;
          }
          else
          {
            // Monochrome mask
            byte[] maskDataCompressed = fd.Encode(mask.MaskData);
            PdfDictionary pdfMask = new PdfDictionary(document);
            pdfMask.Elements.SetName(Keys.Type, "/XObject");
            pdfMask.Elements.SetName(Keys.Subtype, "/Image");

            this.Owner.irefTable.Add(pdfMask);
            pdfMask.Stream = new PdfStream(maskDataCompressed, pdfMask);
            pdfMask.Elements[Keys.Length] = new PdfInteger(maskDataCompressed.Length);
            pdfMask.Elements[Keys.Filter] = new PdfName("/FlateDecode");
            pdfMask.Elements[Keys.Width] = new PdfInteger(width);
            pdfMask.Elements[Keys.Height] = new PdfInteger(height);
            pdfMask.Elements[Keys.BitsPerComponent] = new PdfInteger(1);
            pdfMask.Elements[Keys.ImageMask] = new PdfBoolean(true);
            Elements[Keys.Mask] = pdfMask.Reference;
          }
        }

        byte[] imageDataCompressed = fd.Encode(imageData);
        byte[] imageDataFaxCompressed = isFaxEncoding ? fd.Encode(imageDataFax) : null;

        bool usesCcittEncoding = false;
        if (isFaxEncoding &&
          (imageDataFax.Length < imageDataCompressed.Length ||
          imageDataFaxCompressed.Length < imageDataCompressed.Length))
        {
          // /CCITTFaxDecode creates the smaller file (with or without /FlateDecode):
          usesCcittEncoding = true;

          if (imageDataFax.Length < imageDataCompressed.Length)
          {
            Stream = new PdfStream(imageDataFax, this);
            Elements[Keys.Length] = new PdfInteger(imageDataFax.Length);
            Elements[Keys.Filter] = new PdfName("/CCITTFaxDecode");
            //PdfArray array2 = new PdfArray(this.document);
            PdfDictionary dictionary = new PdfDictionary();
            if (k != 0)
              dictionary.Elements.Add("/K", new PdfInteger(k));
            if (isBitonal < 0)
              dictionary.Elements.Add("/BlackIs1", new PdfBoolean(true));
            dictionary.Elements.Add("/EndOfBlock", new PdfBoolean(false));
            dictionary.Elements.Add("/Columns", new PdfInteger(width));
            dictionary.Elements.Add("/Rows", new PdfInteger(height));
            //array2.Elements.Add(dictionary);
            Elements[Keys.DecodeParms] = dictionary; // array2;
          }
          else
          {
            Stream = new PdfStream(imageDataFaxCompressed, this);
            Elements[Keys.Length] = new PdfInteger(imageDataFaxCompressed.Length);
            PdfArray arrayFilters = new PdfArray(document);
            arrayFilters.Elements.Add(new PdfName("/FlateDecode"));
            arrayFilters.Elements.Add(new PdfName("/CCITTFaxDecode"));
            Elements[Keys.Filter] = arrayFilters;
            PdfArray arrayDecodeParms = new PdfArray(document);

            PdfDictionary dictFlateDecodeParms = new PdfDictionary();
            //dictFlateDecodeParms.Elements.Add("/Columns", new PdfInteger(1));

            PdfDictionary dictCcittFaxDecodeParms = new PdfDictionary();
            if (k != 0)
              dictCcittFaxDecodeParms.Elements.Add("/K", new PdfInteger(k));
            if (isBitonal < 0)
              dictCcittFaxDecodeParms.Elements.Add("/BlackIs1", new PdfBoolean(true));
            dictCcittFaxDecodeParms.Elements.Add("/EndOfBlock", new PdfBoolean(false));
            dictCcittFaxDecodeParms.Elements.Add("/Columns", new PdfInteger(width));
            dictCcittFaxDecodeParms.Elements.Add("/Rows", new PdfInteger(height));

            arrayDecodeParms.Elements.Add(dictFlateDecodeParms); // How to add the "null object"?
            arrayDecodeParms.Elements.Add(dictCcittFaxDecodeParms);
            Elements[Keys.DecodeParms] = arrayDecodeParms;
          }
        }
        else
        {
          // /FlateDecode creates the smaller file (or no monochrome bitmap):
          Stream = new PdfStream(imageDataCompressed, this);
          Elements[Keys.Length] = new PdfInteger(imageDataCompressed.Length);
          Elements[Keys.Filter] = new PdfName("/FlateDecode");
        }

        Elements[Keys.Width] = new PdfInteger(width);
        Elements[Keys.Height] = new PdfInteger(height);
        Elements[Keys.BitsPerComponent] = new PdfInteger(bits);
        // TODO: CMYK

        // CCITT encoding: we need color palette for isBitonal == 0
        // FlateDecode: we need color palette for isBitonal <= 0 unless we have grayscales
        if ((usesCcittEncoding && isBitonal == 0) ||
          (!usesCcittEncoding && isBitonal <= 0  && !isGray))
        {
          PdfArray arrayColorSpace = new PdfArray(document);
          arrayColorSpace.Elements.Add(new PdfName("/Indexed"));
          arrayColorSpace.Elements.Add(new PdfName("/DeviceRGB"));
          arrayColorSpace.Elements.Add(new PdfInteger(paletteColors - 1));
          // ReSharper disable PossibleNullReferenceException
          arrayColorSpace.Elements.Add(colorPalette.Reference);
          // ReSharper restore PossibleNullReferenceException
          Elements[Keys.ColorSpace] = arrayColorSpace;
        }
        else
        {
          Elements[Keys.ColorSpace] = new PdfName("/DeviceGray");
        }
        if (image.Interpolate)
          Elements[Keys.Interpolate] = PdfBoolean.True;
      }
    }
Exemple #5
0
        private void CreateTrueColorMemoryBitmap(int components, int bits, bool hasAlpha)
        {
            int pdfVersion = Owner.Version;
            FlateDecode fd = new FlateDecode();
            ImageDataBitmap idb = (ImageDataBitmap)_image._importedImage.ImageData;
            ImageInformation ii = _image._importedImage.Information;
            bool hasMask = idb.AlphaMaskLength > 0 || idb.BitmapMaskLength > 0;
            bool hasAlphaMask = idb.AlphaMaskLength > 0;

            if (hasMask)
            {
                // monochrome mask is either sufficient or
                // provided for compatibility with older reader versions
                byte[] maskDataCompressed = fd.Encode(idb.BitmapMask, _document.Options.FlateEncodeMode);
                PdfDictionary pdfMask = new PdfDictionary(_document);
                pdfMask.Elements.SetName(Keys.Type, "/XObject");
                pdfMask.Elements.SetName(Keys.Subtype, "/Image");

                Owner._irefTable.Add(pdfMask);
                pdfMask.Stream = new PdfStream(maskDataCompressed, pdfMask);
                pdfMask.Elements[PdfStream.Keys.Length] = new PdfInteger(maskDataCompressed.Length);
                pdfMask.Elements[PdfStream.Keys.Filter] = new PdfName("/FlateDecode");
                pdfMask.Elements[Keys.Width] = new PdfInteger((int)ii.Width);
                pdfMask.Elements[Keys.Height] = new PdfInteger((int)ii.Height);
                pdfMask.Elements[Keys.BitsPerComponent] = new PdfInteger(1);
                pdfMask.Elements[Keys.ImageMask] = new PdfBoolean(true);
                Elements[Keys.Mask] = pdfMask.Reference;
            }
            if (hasMask && hasAlphaMask && pdfVersion >= 14)
            {
                // The image provides an alpha mask (requires Arcrobat 5.0 or higher)
                byte[] alphaMaskCompressed = fd.Encode(idb.AlphaMask, _document.Options.FlateEncodeMode);
                PdfDictionary smask = new PdfDictionary(_document);
                smask.Elements.SetName(Keys.Type, "/XObject");
                smask.Elements.SetName(Keys.Subtype, "/Image");

                Owner._irefTable.Add(smask);
                smask.Stream = new PdfStream(alphaMaskCompressed, smask);
                smask.Elements[PdfStream.Keys.Length] = new PdfInteger(alphaMaskCompressed.Length);
                smask.Elements[PdfStream.Keys.Filter] = new PdfName("/FlateDecode");
                smask.Elements[Keys.Width] = new PdfInteger((int)ii.Width);
                smask.Elements[Keys.Height] = new PdfInteger((int)ii.Height);
                smask.Elements[Keys.BitsPerComponent] = new PdfInteger(8);
                smask.Elements[Keys.ColorSpace] = new PdfName("/DeviceGray");
                Elements[Keys.SMask] = smask.Reference;
            }

            byte[] imageDataCompressed = fd.Encode(idb.Data, _document.Options.FlateEncodeMode);

            Stream = new PdfStream(imageDataCompressed, this);
            Elements[PdfStream.Keys.Length] = new PdfInteger(imageDataCompressed.Length);
            Elements[PdfStream.Keys.Filter] = new PdfName("/FlateDecode");
            Elements[Keys.Width] = new PdfInteger((int)ii.Width);
            Elements[Keys.Height] = new PdfInteger((int)ii.Height);
            Elements[Keys.BitsPerComponent] = new PdfInteger(8);
            // TODO: CMYK
            Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB");
            if (_image.Interpolate)
                Elements[Keys.Interpolate] = PdfBoolean.True;
        }
Exemple #6
0
    /// <summary>
    /// Creates the keys for a JPEG image.
    /// </summary>
    void InitializeJpeg()
    {
      // PDF support JPEG, so there's not much to be done
      MemoryStream memory;
      byte[] imageBits = null;
      int streamLength = 0;
#if GDI
      memory = new MemoryStream();
      image.gdiImage.Save(memory, ImageFormat.Jpeg);
      if ((int)memory.Length == 0)
      {
        Debug.Assert(false, "Internal error? JPEG image, but file not found!");
      }
#endif
#if WPF && !SILVERLIGHT
      // AGHACK
      //string filename = XImage.GetImageFilename(image.wpfImage);
      //if (XImage.ReadJpegFile(filename, -1, ref imageBits))
      //{
      //  streamLength = imageBits.Length;
      //}
      //else
      //  imageBits = null;
      memory = image.Memory;
#endif
      if (imageBits == null)
      {
        streamLength = (int)memory.Length;
        imageBits = new byte[streamLength];
        memory.Seek(0, SeekOrigin.Begin);
        memory.Read(imageBits, 0, streamLength);
        memory.Close();
      }

      FlateDecode fd = new FlateDecode();
      byte[] imageDataCompressed = fd.Encode(imageBits);
      if (imageDataCompressed.Length < imageBits.Length)
      {
        Stream = new PdfStream(imageDataCompressed, this);
        Elements[Keys.Length] = new PdfInteger(imageDataCompressed.Length);
        PdfArray arrayFilters = new PdfArray(document);
        arrayFilters.Elements.Add(new PdfName("/FlateDecode"));
        arrayFilters.Elements.Add(new PdfName("/DCTDecode"));
        Elements[Keys.Filter] = arrayFilters;
      }
      else
      {
        Stream = new PdfStream(imageBits, this);
        Elements[Keys.Length] = new PdfInteger(streamLength);
        Elements[Keys.Filter] = new PdfName("/DCTDecode");
      }
      Elements[Keys.Width] = new PdfInteger(image.PixelWidth);
      Elements[Keys.Height] = new PdfInteger(image.PixelHeight);
      Elements[Keys.BitsPerComponent] = new PdfInteger(8);
#if GDI
      if ((image.gdiImage.Flags & ((int)ImageFlags.ColorSpaceCmyk | (int)ImageFlags.ColorSpaceYcck)) != 0)
      {
        // TODO: Test with CMYK JPEG files
        // THHO: I only found ImageFlags.ColorSpaceYcck JPEG files ...
        Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK");
        if ((image.gdiImage.Flags & (int)ImageFlags.ColorSpaceYcck) != 0)
          Elements["/Decode"] = new PdfLiteral("[1 0 1 0 1 0 1 0]");  // Invert colors? Why??
      }
      else if ((image.gdiImage.Flags & (int)ImageFlags.ColorSpaceGray) != 0)
      {
        Elements[Keys.ColorSpace] = new PdfName("/DeviceGray");
      }
      else
      {
        Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB");
      }
#endif
#if WPF
      // TODOWPF
      // WPFTHHO
#if !SILVERLIGHT
      string pixelFormat = image.wpfImage.Format.ToString();
#else
      string pixelFormat = "xxx";
#endif
      bool isCmyk = image.IsCmyk;
      bool isGrey = pixelFormat == "Gray8";
      if (isCmyk)
      {
        // TODO: Test with CMYK JPEG files
        // THHO: I only found ImageFlags.ColorSpaceYcck JPEG files ...
        Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK");
        Elements["/Decode"] = new PdfLiteral("[1 0 1 0 1 0 1 0]");  // Invert colors? Why??
      }
      else if (isGrey)
      {
        Elements[Keys.ColorSpace] = new PdfName("/DeviceGray");
      }
      else
      {
        Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB");
      }
#endif
    }
Exemple #7
0
        private void CreateIndexedMemoryBitmap(int bits)
        {
            ImageDataBitmap idb = (ImageDataBitmap)_image._importedImage.ImageData;
            ImageInformation ii = _image._importedImage.Information;

            int pdfVersion = Owner.Version;
            int firstMaskColor = -1, lastMaskColor = -1;
            bool segmentedColorMask = idb.SegmentedColorMask;

            {

                FlateDecode fd = new FlateDecode();
                if (firstMaskColor != -1 &&
                  lastMaskColor != -1)
                {
                    // Color mask requires Reader 4.0 or higher:
                    //if (!segmentedColorMask && pdfVersion >= 13)
                    if (!segmentedColorMask && pdfVersion >= 13 && !idb.IsGray)
                    {
                        PdfArray array = new PdfArray(_document);
                        array.Elements.Add(new PdfInteger(firstMaskColor));
                        array.Elements.Add(new PdfInteger(lastMaskColor));
                        Elements[Keys.Mask] = array;
                    }
                    else
                    {
                        // Monochrome mask
                        byte[] maskDataCompressed = fd.Encode(idb.BitmapMask, _document.Options.FlateEncodeMode);
                        PdfDictionary pdfMask = new PdfDictionary(_document);
                        pdfMask.Elements.SetName(Keys.Type, "/XObject");
                        pdfMask.Elements.SetName(Keys.Subtype, "/Image");

                        Owner._irefTable.Add(pdfMask);
                        pdfMask.Stream = new PdfStream(maskDataCompressed, pdfMask);
                        pdfMask.Elements[PdfStream.Keys.Length] = new PdfInteger(maskDataCompressed.Length);
                        pdfMask.Elements[PdfStream.Keys.Filter] = new PdfName("/FlateDecode");
                        pdfMask.Elements[Keys.Width] = new PdfInteger((int)ii.Width);
                        pdfMask.Elements[Keys.Height] = new PdfInteger((int)ii.Height);
                        pdfMask.Elements[Keys.BitsPerComponent] = new PdfInteger(1);
                        pdfMask.Elements[Keys.ImageMask] = new PdfBoolean(true);
                        Elements[Keys.Mask] = pdfMask.Reference;
                    }
                }

                byte[] imageDataCompressed = fd.Encode(idb.Data, _document.Options.FlateEncodeMode);
                byte[] imageDataFaxCompressed = idb.DataFax != null ? fd.Encode(idb.DataFax, _document.Options.FlateEncodeMode) : null;

                bool usesCcittEncoding = false;
                if (idb.DataFax != null &&
                  (idb.LengthFax < imageDataCompressed.Length ||
                  imageDataFaxCompressed.Length < imageDataCompressed.Length))
                {
                    // /CCITTFaxDecode creates the smaller file (with or without /FlateDecode):
                    usesCcittEncoding = true;

                    if (idb.LengthFax < imageDataCompressed.Length)
                    {
                        Stream = new PdfStream(idb.DataFax, this);
                        Elements[PdfStream.Keys.Length] = new PdfInteger(idb.LengthFax);
                        Elements[PdfStream.Keys.Filter] = new PdfName("/CCITTFaxDecode");
                        //PdfArray array2 = new PdfArray(_document);
                        PdfDictionary dictionary = new PdfDictionary();
                        if (idb.K != 0)
                            dictionary.Elements.Add("/K", new PdfInteger(idb.K));
                        if (idb.IsBitonal < 0)
                            dictionary.Elements.Add("/BlackIs1", new PdfBoolean(true));
                        dictionary.Elements.Add("/EndOfBlock", new PdfBoolean(false));
                        dictionary.Elements.Add("/Columns", new PdfInteger((int)ii.Width));
                        dictionary.Elements.Add("/Rows", new PdfInteger((int)ii.Height));
                        //array2.Elements.Add(dictionary);
                        Elements[PdfStream.Keys.DecodeParms] = dictionary; // array2;
                    }
                    else
                    {
                        Stream = new PdfStream(imageDataFaxCompressed, this);
                        Elements[PdfStream.Keys.Length] = new PdfInteger(imageDataFaxCompressed.Length);
                        PdfArray arrayFilters = new PdfArray(_document);
                        arrayFilters.Elements.Add(new PdfName("/FlateDecode"));
                        arrayFilters.Elements.Add(new PdfName("/CCITTFaxDecode"));
                        Elements[PdfStream.Keys.Filter] = arrayFilters;
                        PdfArray arrayDecodeParms = new PdfArray(_document);

                        PdfDictionary dictFlateDecodeParms = new PdfDictionary();
                        //dictFlateDecodeParms.Elements.Add("/Columns", new PdfInteger(1));

                        PdfDictionary dictCcittFaxDecodeParms = new PdfDictionary();
                        if (idb.K != 0)
                            dictCcittFaxDecodeParms.Elements.Add("/K", new PdfInteger(idb.K));
                        if (idb.IsBitonal < 0)
                            dictCcittFaxDecodeParms.Elements.Add("/BlackIs1", new PdfBoolean(true));
                        dictCcittFaxDecodeParms.Elements.Add("/EndOfBlock", new PdfBoolean(false));
                        dictCcittFaxDecodeParms.Elements.Add("/Columns", new PdfInteger((int)ii.Width));
                        dictCcittFaxDecodeParms.Elements.Add("/Rows", new PdfInteger((int)ii.Height));

                        arrayDecodeParms.Elements.Add(dictFlateDecodeParms); // How to add the "null object"?
                        arrayDecodeParms.Elements.Add(dictCcittFaxDecodeParms);
                        Elements[PdfStream.Keys.DecodeParms] = arrayDecodeParms;
                    }
                }
                else
                {
                    // /FlateDecode creates the smaller file (or no monochrome bitmap):
                    Stream = new PdfStream(imageDataCompressed, this);
                    Elements[PdfStream.Keys.Length] = new PdfInteger(imageDataCompressed.Length);
                    Elements[PdfStream.Keys.Filter] = new PdfName("/FlateDecode");
                }

                Elements[Keys.Width] = new PdfInteger((int)ii.Width);
                Elements[Keys.Height] = new PdfInteger((int)ii.Height);
                Elements[Keys.BitsPerComponent] = new PdfInteger(bits);
                // TODO: CMYK

                // CCITT encoding: we need color palette for isBitonal == 0
                // FlateDecode: we need color palette for isBitonal <= 0 unless we have grayscales
                if ((usesCcittEncoding && idb.IsBitonal == 0) ||
                  (!usesCcittEncoding && idb.IsBitonal <= 0 && !idb.IsGray))
                {
                    PdfDictionary colorPalette = null;
                    colorPalette = new PdfDictionary(_document);
                    byte[] packedPaletteData = idb.PaletteDataLength >= 48 ? fd.Encode(idb.PaletteData, _document.Options.FlateEncodeMode) : null; // don't compress small palettes
                    if (packedPaletteData != null && packedPaletteData.Length + 20 < idb.PaletteDataLength) // +20: compensate for the overhead (estimated value)
                    {
                        // Create compressed color palette:
                        colorPalette.CreateStream(packedPaletteData);
                        colorPalette.Elements[PdfStream.Keys.Length] = new PdfInteger(packedPaletteData.Length);
                        colorPalette.Elements[PdfStream.Keys.Filter] = new PdfName("/FlateDecode");
                    }
                    else
                    {
                        // Create uncompressed color palette:
                        colorPalette.CreateStream(idb.PaletteData);
                        colorPalette.Elements[PdfStream.Keys.Length] = new PdfInteger(idb.PaletteDataLength);
                    }
                    Owner._irefTable.Add(colorPalette);

                    PdfArray arrayColorSpace = new PdfArray(_document);
                    arrayColorSpace.Elements.Add(new PdfName("/Indexed"));
                    arrayColorSpace.Elements.Add(new PdfName("/DeviceRGB"));
                    arrayColorSpace.Elements.Add(new PdfInteger((int)ii.ColorsUsed - 1));
                    arrayColorSpace.Elements.Add(colorPalette.Reference);
                    Elements[Keys.ColorSpace] = arrayColorSpace;
                }
                else
                {
                    Elements[Keys.ColorSpace] = new PdfName("/DeviceGray");
                }
                if (_image.Interpolate)
                    Elements[Keys.Interpolate] = PdfBoolean.True;
            }
        }
Exemple #8
0
        /// <summary>
        /// Creates the keys for a JPEG image.
        /// </summary>
        void InitializeJpeg()
        {
            // PDF supports JPEG, so there's not much to be done.
            MemoryStream memory = null;
            // Close the MemoryStream if we create it.
            bool ownMemory = false;

            byte[] imageBits = null;
            int streamLength = 0;

#if CORE || GDI || WPF
            if (_image._importedImage != null)
            {
                ImageDataDct idd = (ImageDataDct)_image._importedImage.ImageData;
                imageBits = idd.Data;
                streamLength = idd.Length;
            }
#endif

#if CORE || GDI
            if (_image._importedImage == null)
            {
                if (!_image._path.StartsWith("*"))
                {
                    // Image does not come from a stream, so we have the path to the file - just use the path.
                    // If the image was modified in memory, those changes will be lost and the original image, as it was read from the file, will be added to the PDF.
                    using (FileStream sourceFile = File.OpenRead(_image._path))
                    {
                        int count;
                        byte[] buffer = new byte[8192];
                        memory = new MemoryStream((int)sourceFile.Length);
                        ownMemory = true;
                        do
                        {
                            count = sourceFile.Read(buffer, 0, buffer.Length);
                            // memory.Write(buffer, 0, buffer.Length);
                            memory.Write(buffer, 0, count);
                        } while (count > 0);
                    }
                }
                else
                {
                    memory = new MemoryStream();
                    ownMemory = true;
                    // If we have a stream, copy data from the stream.
                    if (_image._stream != null && _image._stream.CanSeek)
                    {
                        Stream stream = _image._stream;
                        stream.Seek(0, SeekOrigin.Begin);
                        byte[] buffer = new byte[32 * 1024]; // 32K buffer.
                        int bytesRead;
                        while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            memory.Write(buffer, 0, bytesRead);
                        }
                    }
                    else
                    {
#if CORE_WITH_GDI
                        // No stream, no filename, get image data.
                        // Save the image to a memory stream.
                        _image._gdiImage.Save(memory, ImageFormat.Jpeg);
#endif
                    }
                }

                if ((int)memory.Length == 0)
                {
                    Debug.Assert(false, "Internal error? JPEG image, but file not found!");
                }
            }
#endif
#if WPF
            // AGHACK
            //string filename = XImage.GetImageFilename(image._wpfImage);
            //if (XImage.ReadJpegFile(filename, -1, ref imageBits))
            //{
            //  streamLength = imageBits.Length;
            //}
            //else
            //  imageBits = null;
#if !SILVERLIGHT
            memory = _image.Memory;
#else
            memory = new MemoryStream();
            ownMemory = true;
#endif
#endif
#if NETFX_CORE
            memory = new MemoryStream();
            ownMemory = true;
#endif
            // THHO4THHO Use ImageImporterJPEG here to avoid redundant code.

            if (imageBits == null)
            {
                streamLength = (int)memory.Length;
                imageBits = new byte[streamLength];
                memory.Seek(0, SeekOrigin.Begin);
                memory.Read(imageBits, 0, streamLength);
                // ReSharper disable once ConditionIsAlwaysTrueOrFalse
                if (ownMemory)
                {
#if UWP || true
                    memory.Dispose();
#else
                memory.Close();
#endif
                }
            }

            bool tryFlateDecode = _document.Options.UseFlateDecoderForJpegImages == PdfUseFlateDecoderForJpegImages.Automatic;
            bool useFlateDecode = _document.Options.UseFlateDecoderForJpegImages == PdfUseFlateDecoderForJpegImages.Always;

            FlateDecode fd = new FlateDecode();
            byte[] imageDataCompressed = (useFlateDecode || tryFlateDecode) ? fd.Encode(imageBits, _document.Options.FlateEncodeMode) : null;
            if (useFlateDecode || tryFlateDecode && imageDataCompressed.Length < imageBits.Length)
            {
                Stream = new PdfStream(imageDataCompressed, this);
                Elements[PdfStream.Keys.Length] = new PdfInteger(imageDataCompressed.Length);
                PdfArray arrayFilters = new PdfArray(_document);
                arrayFilters.Elements.Add(new PdfName("/FlateDecode"));
                arrayFilters.Elements.Add(new PdfName("/DCTDecode"));
                Elements[PdfStream.Keys.Filter] = arrayFilters;
            }
            else
            {
                Stream = new PdfStream(imageBits, this);
                Elements[PdfStream.Keys.Length] = new PdfInteger(streamLength);
                Elements[PdfStream.Keys.Filter] = new PdfName("/DCTDecode");
            }
            if (_image.Interpolate)
                Elements[Keys.Interpolate] = PdfBoolean.True;
            Elements[Keys.Width] = new PdfInteger(_image.PixelWidth);
            Elements[Keys.Height] = new PdfInteger(_image.PixelHeight);
            Elements[Keys.BitsPerComponent] = new PdfInteger(8);

#if CORE || GDI || WPF
            if (_image._importedImage != null)
            {
                if (_image._importedImage.Information.ImageFormat == ImageInformation.ImageFormats.JPEGCMYK ||
                    _image._importedImage.Information.ImageFormat == ImageInformation.ImageFormats.JPEGRGBW)
                {
                    // TODO: Test with CMYK JPEG files (so far I only found ImageFlags.ColorSpaceYcck JPEG files ...)
                    Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK");
                    if (_image._importedImage.Information.ImageFormat == ImageInformation.ImageFormats.JPEGRGBW)
                        Elements["/Decode"] = new PdfLiteral("[1 0 1 0 1 0 1 0]"); // Invert colors from RGBW to CMYK.
                }
                else if (_image._importedImage.Information.ImageFormat == ImageInformation.ImageFormats.JPEGGRAY)
                {
                    Elements[Keys.ColorSpace] = new PdfName("/DeviceGray");
                }
                else
                {
                    Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB");
                }
            }
#endif
#if CORE_WITH_GDI
            if (_image._importedImage == null)
            {
                if ((_image._gdiImage.Flags & ((int)ImageFlags.ColorSpaceCmyk | (int)ImageFlags.ColorSpaceYcck)) != 0)
                {
                    // TODO: Test with CMYK JPEG files (so far I only found ImageFlags.ColorSpaceYcck JPEG files ...)
                    Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK");
                    if ((_image._gdiImage.Flags & (int)ImageFlags.ColorSpaceYcck) != 0)
                        Elements["/Decode"] = new PdfLiteral("[1 0 1 0 1 0 1 0]"); // Invert colors? Why??
                }
                else if ((_image._gdiImage.Flags & (int)ImageFlags.ColorSpaceGray) != 0)
                {
                    Elements[Keys.ColorSpace] = new PdfName("/DeviceGray");
                }
                else
                {
                    Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB");
                }
            }
#endif
#if GDI
            if (_image._importedImage == null)
            {
                if ((_image._gdiImage.Flags & ((int)ImageFlags.ColorSpaceCmyk | (int)ImageFlags.ColorSpaceYcck)) != 0)
                {
                    // TODO: Test with CMYK JPEG files (so far I only found ImageFlags.ColorSpaceYcck JPEG files ...)
                    Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK");
                    if ((_image._gdiImage.Flags & (int)ImageFlags.ColorSpaceYcck) != 0)
                        Elements["/Decode"] = new PdfLiteral("[1 0 1 0 1 0 1 0]"); // Invert colors? Why??
                }
                else if ((_image._gdiImage.Flags & (int)ImageFlags.ColorSpaceGray) != 0)
                {
                    Elements[Keys.ColorSpace] = new PdfName("/DeviceGray");
                }
                else
                {
                    Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB");
                }
            }
#endif
#if WPF
            // TODOSILVERLIGHT
#if !SILVERLIGHT
            string pixelFormat = _image._wpfImage.Format.ToString();
#else
            string pixelFormat = "xxx";
#endif
            bool isCmyk = _image.IsCmyk;
            bool isGrey = pixelFormat == "Gray8";
            if (isCmyk)
            {
                // TODO: Test with CMYK JPEG files (so far I only found ImageFlags.ColorSpaceYcck JPEG files ...)
                Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK");
                Elements["/Decode"] = new PdfLiteral("[1 0 1 0 1 0 1 0]");  // Invert colors? Why??
            }
            else if (isGrey)
            {
                Elements[Keys.ColorSpace] = new PdfName("/DeviceGray");
            }
            else
            {
                Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB");
            }
#endif
        }
Exemple #9
0
        private void ReadTrueColorMemoryBitmapAg(int components, int bits, bool hasAlpha)
        {
            int pdfVersion = Owner.Version;
            MemoryStream memory = new MemoryStream();

            WriteableBitmap bitmap = null;
            if (_image._wpfImage is WriteableBitmap)
                bitmap = (WriteableBitmap)_image._wpfImage;
            else if (_image._wpfImage is BitmapImage)
                bitmap = new WriteableBitmap(_image._wpfImage);

            if (bitmap != null)
            {
                int height = _image.PixelHeight;
                int width = _image.PixelWidth;

                int logicalComponents = components;
                if (components == 4)
                    logicalComponents = 3;

                byte[] imageData = new byte[components * width * height];

                bool hasMask = false;
                bool hasAlphaMask = false;
                byte[] alphaMask = hasAlpha ? new byte[width * height] : null;
                MonochromeMask mask = hasAlpha ? new MonochromeMask(width, height) : null;

                int nOffsetRead = 0;
                if (logicalComponents == 3)
                {
                    for (int y = 0; y < height; ++y)
                    {
                        int nOffsetWrite = 3 * y * width; // 3*(height - 1 - y)*width;
                        int nOffsetWriteAlpha = 0;
                        if (hasAlpha)
                        {
                            mask.StartLine(y);
                            nOffsetWriteAlpha = y * width; // (height - 1 - y) * width;
                        }

                        for (int x = 0; x < width; ++x)
                        {
                            uint pixel = (uint)bitmap.Pixels[nOffsetRead];
                            imageData[nOffsetWrite] = (byte)(pixel >> 16);
                            imageData[nOffsetWrite + 1] = (byte)(pixel >> 8);
                            imageData[nOffsetWrite + 2] = (byte)(pixel);
                            if (hasAlpha)
                            {
                                byte pel = (byte)(pixel >> 24);
                                mask.AddPel(pel);
                                alphaMask[nOffsetWriteAlpha] = pel;
                                if (!hasMask || !hasAlphaMask)
                                {
                                    if (pel != 255)
                                    {
                                        hasMask = true;
                                        if (pel != 0)
                                            hasAlphaMask = true;
                                    }
                                }
                                ++nOffsetWriteAlpha;
                            }
                            //nOffsetRead += hasAlpha ? 4 : components;
                            ++nOffsetRead;
                            nOffsetWrite += 3;
                        }
                        //nOffsetRead = 4*((nOffsetRead + 3)/4); // Align to 32 bit boundary
                    }
                }
                else if (components == 1)
                {
                    // Grayscale
                    throw new NotImplementedException("Image format not supported (grayscales).");
                }

                FlateDecode fd = new FlateDecode();
                if (hasMask)
                {
                    // monochrome mask is either sufficient or
                    // provided for compatibility with older reader versions
                    byte[] maskDataCompressed = fd.Encode(mask.MaskData, _document.Options.FlateEncodeMode);
                    PdfDictionary pdfMask = new PdfDictionary(_document);
                    pdfMask.Elements.SetName(Keys.Type, "/XObject");
                    pdfMask.Elements.SetName(Keys.Subtype, "/Image");

                    Owner._irefTable.Add(pdfMask);
                    pdfMask.Stream = new PdfStream(maskDataCompressed, pdfMask);
                    pdfMask.Elements[Keys.Length] = new PdfInteger(maskDataCompressed.Length);
                    pdfMask.Elements[Keys.Filter] = new PdfName("/FlateDecode");
                    pdfMask.Elements[Keys.Width] = new PdfInteger(width);
                    pdfMask.Elements[Keys.Height] = new PdfInteger(height);
                    pdfMask.Elements[Keys.BitsPerComponent] = new PdfInteger(1);
                    pdfMask.Elements[Keys.ImageMask] = new PdfBoolean(true);
                    Elements[Keys.Mask] = pdfMask.Reference;
                }
                if (hasMask && hasAlphaMask && pdfVersion >= 14)
                {
                    // The image provides an alpha mask (requires Arcrobat 5.0 or higher)
                    byte[] alphaMaskCompressed = fd.Encode(alphaMask, _document.Options.FlateEncodeMode);
                    PdfDictionary smask = new PdfDictionary(_document);
                    smask.Elements.SetName(Keys.Type, "/XObject");
                    smask.Elements.SetName(Keys.Subtype, "/Image");

                    Owner._irefTable.Add(smask);
                    smask.Stream = new PdfStream(alphaMaskCompressed, smask);
                    smask.Elements[Keys.Length] = new PdfInteger(alphaMaskCompressed.Length);
                    smask.Elements[Keys.Filter] = new PdfName("/FlateDecode");
                    smask.Elements[Keys.Width] = new PdfInteger(width);
                    smask.Elements[Keys.Height] = new PdfInteger(height);
                    smask.Elements[Keys.BitsPerComponent] = new PdfInteger(8);
                    smask.Elements[Keys.ColorSpace] = new PdfName("/DeviceGray");
                    Elements[Keys.SMask] = smask.Reference;
                }

                byte[] imageDataCompressed = fd.Encode(imageData, _document.Options.FlateEncodeMode);

                Stream = new PdfStream(imageDataCompressed, this);
                Elements[Keys.Length] = new PdfInteger(imageDataCompressed.Length);
                Elements[Keys.Filter] = new PdfName("/FlateDecode");
                Elements[Keys.Width] = new PdfInteger(width);
                Elements[Keys.Height] = new PdfInteger(height);
                Elements[Keys.BitsPerComponent] = new PdfInteger(8);
                // TODO: CMYK
                Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB");
                if (_image.Interpolate)
                    Elements[Keys.Interpolate] = PdfBoolean.True;
            }
        }
Exemple #10
0
    /* BITMAPINFOHEADER struct and byte offsets:
        typedef struct tagBITMAPINFOHEADER{
          DWORD  biSize;           // 14
          LONG   biWidth;          // 18
          LONG   biHeight;         // 22
          WORD   biPlanes;         // 26
          WORD   biBitCount;       // 28
          DWORD  biCompression;    // 30
          DWORD  biSizeImage;      // 34
          LONG   biXPelsPerMeter;  // 38
          LONG   biYPelsPerMeter;  // 42
          DWORD  biClrUsed;        // 46
          DWORD  biClrImportant;   // 50
        } BITMAPINFOHEADER, *PBITMAPINFOHEADER; 
    */

    private void ReadIndexedMemoryBitmap(int bits, ref bool hasAlpha)
    {
#if DEBUG_
      image.image.Save("$$$.bmp", ImageFormat.Bmp);
#endif
      int pdfVersion = this.Owner.Version;
      int firstMaskColor = -1, lastMaskColor = -1;
      bool segmentedColorMask = false;

      MemoryStream memory = new MemoryStream();
#if GDI
      image.gdiImage.Save(memory, ImageFormat.Bmp);
#endif
#if WPF
      // WPFTHHO: StL: keine Ahnung ob das so stimmt.
      BmpBitmapEncoder encoder = new BmpBitmapEncoder();
      encoder.Frames.Add(BitmapFrame.Create(this.image.wpfImage));
      encoder.Save(memory);
#endif
      int streamLength = (int)memory.Length;
      Debug.Assert(streamLength > 0, "Bitmap image encoding failed.");
      if (streamLength > 0)
      {
        byte[] imageBits = new byte[streamLength];
        memory.Seek(0, SeekOrigin.Begin);
        memory.Read(imageBits, 0, streamLength);
        memory.Close();

        int height = this.image.PixelHeight;
        int width = this.image.PixelWidth;

        if (ReadWord(imageBits, 0) != 0x4d42 || // "BM"
          ReadDWord(imageBits, 2) != streamLength ||
          ReadDWord(imageBits, 14) != 40 || // sizeof BITMAPINFOHEADER
#if WPF
          // TODOWPF: bug with height and width
          false)
#else
          ReadDWord(imageBits, 18) != width ||
          ReadDWord(imageBits, 22) != height)
#endif
        {
          throw new NotImplementedException("ReadIndexedMemoryBitmap: unsupported format");
        }
#if WPF
        // TODOWPF: bug with height and width
        width = ReadDWord(imageBits, 18);
        height = ReadDWord(imageBits, 22);
#endif
        if (ReadWord(imageBits, 26) != 1 ||
            ReadWord(imageBits, 28) != bits ||
            ReadDWord(imageBits, 30) != 0)
        {
          throw new NotImplementedException("ReadIndexedMemoryBitmap: unsupported format #2");
        }

        int bytesFileOffset = ReadDWord(imageBits, 10);
        int bytesColorPaletteOffset = 0x36; // GDI+ always returns Windows bitmaps: sizeof BITMAPFILEHEADER + sizeof BITMAPINFOHEADER
        int paletteColors = ReadDWord(imageBits, 46);
        if ((bytesFileOffset - bytesColorPaletteOffset) / 4 != paletteColors)
        {
          throw new NotImplementedException("ReadIndexedMemoryBitmap: unsupported format #3");
        }

        MonochromeMask mask = new MonochromeMask(width, height);

        byte[] paletteData = new byte[3 * paletteColors];
        for (int color = 0; color < paletteColors; ++color)
        {
          paletteData[3 * color] = imageBits[bytesColorPaletteOffset + 4 * color + 2];
          paletteData[3 * color + 1] = imageBits[bytesColorPaletteOffset + 4 * color + 1];
          paletteData[3 * color + 2] = imageBits[bytesColorPaletteOffset + 4 * color + 0];
          if (imageBits[bytesColorPaletteOffset + 4 * color + 3] < 128)
          {
            // We treat this as transparency:
            if (firstMaskColor == -1)
              firstMaskColor = color;
            if (lastMaskColor == -1 || lastMaskColor == color - 1)
              lastMaskColor = color;
            if (lastMaskColor != color)
              segmentedColorMask = true;
          }
          else
          {
            // We treat this as opacity:
          }
        }

        // NYI: (no sample found where this was required) 
        // if (segmentedColorMask = true)
        // { ... }

        FlateDecode fd = new FlateDecode();
        PdfDictionary colorPalette = new PdfDictionary(this.document);
        // TODO: decide at run-time if compression makes sense
#if false
        // Create uncompressed color palette:
        colorPalette.CreateStream(paletteData);
        colorPalette.Elements[Keys.Length] = new PdfInteger(paletteData.Length);
#else
        // Create compressed color palette:
        byte[] packedPaletteData = fd.Encode(paletteData);
        colorPalette.CreateStream(packedPaletteData);
        colorPalette.Elements[Keys.Length] = new PdfInteger(packedPaletteData.Length);
        colorPalette.Elements[Keys.Filter] = new PdfName("/FlateDecode");
#endif
        this.Owner.irefTable.Add(colorPalette);

        byte[] imageData = new byte[1 * width * height];

        int bytesOffsetRead = 0;
        if (bits == 8 || bits == 4 || bits == 1)
        {
          int bytesPerLine = (width * bits + 7) / 8;
          for (int y = 0; y < height; ++y)
          {
            mask.StartLine(y);
            int bytesOffsetWrite = (height - 1 - y) * ((width * bits + 7) / 8);
            for (int x = 0; x < bytesPerLine; ++x)
            {
              imageData[bytesOffsetWrite] = imageBits[bytesFileOffset + bytesOffsetRead];
              if (firstMaskColor != -1)
              {
                int n = imageBits[bytesFileOffset + bytesOffsetRead];
                if (bits == 8)
                {
                  // TODO???: segmentedColorMask == true => falsche Maske NYI
                  mask.AddPel((n >= firstMaskColor) && (n <= lastMaskColor));
                }
                else if (bits == 4)
                {
                  // TODO???: segmentedColorMask == true => falsche Maske NYI
                  int n1 = (n & 0xf0) / 16;
                  int n2 = (n & 0x0f);
                  mask.AddPel((n1 >= firstMaskColor) && (n1 <= lastMaskColor));
                  mask.AddPel((n2 >= firstMaskColor) && (n2 <= lastMaskColor));
                }
                else if (bits == 1)
                {
                  // TODO???: segmentedColorMask == true => bad mask NYI
                  for (int bit = 1; bit <= 8; ++bit)
                  {
                    int n1 = (n & 0x80) / 128;
                    mask.AddPel((n1 >= firstMaskColor) && (n1 <= lastMaskColor));
                    n *= 2;
                  }
                }
              }
              bytesOffsetRead += 1;
              bytesOffsetWrite += 1;
            }
            bytesOffsetRead = 4 * ((bytesOffsetRead + 3) / 4); // Align to 32 bit boundary
          }
        }
        else
        {
          throw new NotImplementedException("ReadIndexedMemoryBitmap: unsupported format #3");
        }

        if (firstMaskColor != -1 &&
          lastMaskColor != -1)
        {
          // Color mask requires Reader 4.0 or higher:
          if (!segmentedColorMask && pdfVersion >= 13)
          {
            PdfArray array = new PdfArray(this.document);
            array.Elements.Add(new PdfInteger(firstMaskColor));
            array.Elements.Add(new PdfInteger(lastMaskColor));
            Elements[Keys.Mask] = array;
          }
          else
          {
            // Monochrome mask
            byte[] maskDataCompressed = fd.Encode(mask.MaskData);
            PdfDictionary pdfMask = new PdfDictionary(this.document);
            pdfMask.Elements.SetName(Keys.Type, "/XObject");
            pdfMask.Elements.SetName(Keys.Subtype, "/Image");

            this.Owner.irefTable.Add(pdfMask);
            pdfMask.Stream = new PdfStream(maskDataCompressed, pdfMask);
            pdfMask.Elements[Keys.Length] = new PdfInteger(maskDataCompressed.Length);
            pdfMask.Elements[Keys.Filter] = new PdfName("/FlateDecode");
            pdfMask.Elements[Keys.Width] = new PdfInteger(width);
            pdfMask.Elements[Keys.Height] = new PdfInteger(height);
            pdfMask.Elements[Keys.BitsPerComponent] = new PdfInteger(1);
            pdfMask.Elements[Keys.ImageMask] = new PdfBoolean(true);
            Elements[Keys.Mask] = pdfMask.Reference;
          }
        }

        byte[] imageDataCompressed = fd.Encode(imageData);

        Stream = new PdfStream(imageDataCompressed, this);
        Elements[Keys.Length] = new PdfInteger(imageDataCompressed.Length);
        Elements[Keys.Filter] = new PdfName("/FlateDecode");
        Elements[Keys.Width] = new PdfInteger(width);
        Elements[Keys.Height] = new PdfInteger(height);
        Elements[Keys.BitsPerComponent] = new PdfInteger(bits);
        PdfArray array2 = new PdfArray(this.document);
        array2.Elements.Add(new PdfName("/Indexed"));
        // TODO: CMYK
        array2.Elements.Add(new PdfName("/DeviceRGB"));
        array2.Elements.Add(new PdfInteger(paletteColors - 1));
        array2.Elements.Add(colorPalette.Reference);
        Elements[Keys.ColorSpace] = array2;
      }
    }
Exemple #11
0
        /// <summary>
        /// Gets the filter specified by the case sensitive name.
        /// </summary>
        public static Filter GetFilter(string filterName)
        {
            if (filterName.StartsWith("/"))
                filterName = filterName.Substring(1);

            // Some tools use abbreviations
            switch (filterName)
            {
                case "ASCIIHexDecode":
                case "AHx":
                    return _asciiHexDecode ?? (_asciiHexDecode = new AsciiHexDecode());

                case "ASCII85Decode":
                case "A85":
                    return _ascii85Decode ?? (_ascii85Decode = new Ascii85Decode());

                case "LZWDecode":
                case "LZW":
                    return _lzwDecode ?? (_lzwDecode = new LzwDecode());

                case "FlateDecode":
                case "Fl":
                    return _flateDecode ?? (_flateDecode = new FlateDecode());

                //case "RunLengthDecode":
                //  if (RunLengthDecode == null)
                //    RunLengthDecode = new RunLengthDecode();
                //  return RunLengthDecode;
                //
                //case "CCITTFaxDecode":
                //  if (CCITTFaxDecode == null)
                //    CCITTFaxDecode = new CCITTFaxDecode();
                //  return CCITTFaxDecode;
                //
                //case "JBIG2Decode":
                //  if (JBIG2Decode == null)
                //    JBIG2Decode = new JBIG2Decode();
                //  return JBIG2Decode;
                //
                //case "DCTDecode":
                //  if (DCTDecode == null)
                //    DCTDecode = new DCTDecode();
                //  return DCTDecode;
                //
                //case "JPXDecode":
                //  if (JPXDecode == null)
                //    JPXDecode = new JPXDecode();
                //  return JPXDecode;
                //
                //case "Crypt":
                //  if (Crypt == null)
                //    Crypt = new Crypt();
                //  return Crypt;

                case "RunLengthDecode":
                case "CCITTFaxDecode":
                case "JBIG2Decode":
                case "DCTDecode":
                case "JPXDecode":
                case "Crypt":
                    Debug.WriteLine("Filter not implemented: " + filterName);
                    return null;
            }
            throw new NotImplementedException("Unknown filter: " + filterName);
        }