コード例 #1
0
ファイル: fx_basic_buffer.cpp プロジェクト: abbro-ca/pdfium
void CFX_BinaryBuf::ExpandBuf(FX_STRSIZE add_size)
{
    FX_STRSIZE new_size = add_size + m_DataSize;
    if (m_AllocSize >= new_size) {
        return;
    }
    int alloc_step;
    if (m_AllocStep == 0) {
        alloc_step = m_AllocSize / 4;
        if (alloc_step < 128 ) {
            alloc_step = 128;
        }
    } else {
        alloc_step = m_AllocStep;
    }
    new_size = (new_size + alloc_step - 1) / alloc_step * alloc_step;
    uint8_t* pNewBuffer = m_pBuffer;
    if (pNewBuffer) {
        pNewBuffer = FX_Realloc(uint8_t, m_pBuffer, new_size);
    } else {
        pNewBuffer = FX_Alloc(uint8_t, new_size);
    }
    m_pBuffer = pNewBuffer;
    m_AllocSize = new_size;
}
コード例 #2
0
ファイル: fx_sax_imp.cpp プロジェクト: primiano/pdfium-merge
void CFX_SAXReader::ReallocNameBuffer() {
  if (m_iDataPos < m_iNameSize) {
    return;
  }
  if (m_iNameSize <= 1024 * 1024) {
    m_iNameSize *= 2;
  } else {
    m_iNameSize += 1024 * 1024;
  }
  m_pszName = (uint8_t*)FX_Realloc(uint8_t, m_pszName, m_iNameSize);
}
コード例 #3
0
ファイル: fx_basic_array.cpp プロジェクト: Gardenya/pdfium
FX_BOOL CFX_BasicArray::SetSize(int nNewSize)
{
    if (nNewSize <= 0) {
        FX_Free(m_pData);
        m_pData = NULL;
        m_nSize = m_nMaxSize = 0;
        return 0 == nNewSize;
    }

    if (m_pData == NULL) {
        pdfium::base::CheckedNumeric<int> totalSize = nNewSize;
        totalSize *= m_nUnitSize;
        if (!totalSize.IsValid()) {
            m_nSize = m_nMaxSize = 0;
            return FALSE;
        }
        m_pData = FX_Alloc(FX_BYTE, totalSize.ValueOrDie());
        if (!m_pData) {
            m_nSize = m_nMaxSize = 0;
            return FALSE;
        }
        m_nSize = m_nMaxSize = nNewSize;
    } else if (nNewSize <= m_nMaxSize) {
        if (nNewSize > m_nSize) {
            FXSYS_memset32(m_pData + m_nSize * m_nUnitSize, 0, (nNewSize - m_nSize) * m_nUnitSize);
        }
        m_nSize = nNewSize;
    } else {
        int nNewMax = nNewSize < m_nMaxSize ? m_nMaxSize : nNewSize;
        pdfium::base::CheckedNumeric<int> totalSize = nNewMax;
        totalSize *= m_nUnitSize;
        if (!totalSize.IsValid() || nNewMax < m_nSize) {
            return FALSE;
        }
        FX_LPBYTE pNewData = FX_Realloc(FX_BYTE, m_pData, totalSize.ValueOrDie());
        if (pNewData == NULL) {
            return FALSE;
        }
        FXSYS_memset32(pNewData + m_nSize * m_nUnitSize, 0, (nNewMax - m_nSize) * m_nUnitSize);
        m_pData = pNewData;
        m_nSize = nNewSize;
        m_nMaxSize = nNewMax;
    }
    return TRUE;
}
コード例 #4
0
FX_BOOL CFDE_CSSTextBuf::ExpandBuf(int32_t iDesiredSize) {
  if (m_bExtBuf) {
    return FALSE;
  }
  if (!m_pBuffer) {
    m_pBuffer = FX_Alloc(FX_WCHAR, iDesiredSize);
  } else if (m_iBufLen != iDesiredSize) {
    m_pBuffer = FX_Realloc(FX_WCHAR, m_pBuffer, iDesiredSize);
  } else {
    return TRUE;
  }
  if (!m_pBuffer) {
    m_iBufLen = 0;
    return FALSE;
  }
  m_iBufLen = iDesiredSize;
  return TRUE;
}
コード例 #5
0
bool CFX_BasicArray::SetSize(int nNewSize) {
  if (nNewSize <= 0) {
    FX_Free(m_pData);
    m_pData = nullptr;
    m_nSize = m_nMaxSize = 0;
    return 0 == nNewSize;
  }

  if (!m_pData) {
    pdfium::base::CheckedNumeric<int> totalSize = nNewSize;
    totalSize *= m_nUnitSize;
    if (!totalSize.IsValid()) {
      m_nSize = m_nMaxSize = 0;
      return false;
    }
    m_pData =
        FX_Alloc(uint8_t, pdfium::base::ValueOrDieForType<size_t>(totalSize));
    m_nSize = m_nMaxSize = nNewSize;
  } else if (nNewSize <= m_nMaxSize) {
    if (nNewSize > m_nSize) {
      FXSYS_memset(m_pData + m_nSize * m_nUnitSize, 0,
                   (nNewSize - m_nSize) * m_nUnitSize);
    }
    m_nSize = nNewSize;
  } else {
    int nNewMax = nNewSize < m_nMaxSize ? m_nMaxSize : nNewSize;
    pdfium::base::CheckedNumeric<int> totalSize = nNewMax;
    totalSize *= m_nUnitSize;
    if (!totalSize.IsValid() || nNewMax < m_nSize) {
      return false;
    }
    uint8_t* pNewData = FX_Realloc(
        uint8_t, m_pData, pdfium::base::ValueOrDieForType<size_t>(totalSize));
    if (!pNewData) {
      return false;
    }
    FXSYS_memset(pNewData + m_nSize * m_nUnitSize, 0,
                 (nNewMax - m_nSize) * m_nUnitSize);
    m_pData = pNewData;
    m_nSize = nNewSize;
    m_nMaxSize = nNewMax;
  }
  return true;
}
コード例 #6
0
ファイル: fpdf_page_func.cpp プロジェクト: was4444/pdfium
FX_BOOL CPDF_Function::Init(CPDF_Object* pObj) {
  CPDF_Dictionary* pDict;
  if (pObj->GetType() == PDFOBJ_STREAM) {
    pDict = ((CPDF_Stream*)pObj)->GetDict();
  } else {
    pDict = (CPDF_Dictionary*)pObj;
  }
  CPDF_Array* pDomains = pDict->GetArray(FX_BSTRC("Domain"));
  if (pDomains == NULL) {
    return FALSE;
  }
  m_nInputs = pDomains->GetCount() / 2;
  if (m_nInputs == 0) {
    return FALSE;
  }
  m_pDomains = FX_Alloc2D(FX_FLOAT, m_nInputs, 2);
  for (int i = 0; i < m_nInputs * 2; i++) {
    m_pDomains[i] = pDomains->GetFloat(i);
  }
  CPDF_Array* pRanges = pDict->GetArray(FX_BSTRC("Range"));
  m_nOutputs = 0;
  if (pRanges) {
    m_nOutputs = pRanges->GetCount() / 2;
    m_pRanges = FX_Alloc2D(FX_FLOAT, m_nOutputs, 2);
    for (int i = 0; i < m_nOutputs * 2; i++) {
      m_pRanges[i] = pRanges->GetFloat(i);
    }
  }
  FX_DWORD old_outputs = m_nOutputs;
  if (!v_Init(pObj)) {
    return FALSE;
  }
  if (m_pRanges && m_nOutputs > (int)old_outputs) {
    m_pRanges = FX_Realloc(FX_FLOAT, m_pRanges, m_nOutputs * 2);
    if (m_pRanges) {
      FXSYS_memset(m_pRanges + (old_outputs * 2), 0,
                   sizeof(FX_FLOAT) * (m_nOutputs - old_outputs) * 2);
    }
  }
  return TRUE;
}
コード例 #7
0
ファイル: fgas_utils.cpp プロジェクト: gradescope/pdfium
uint8_t* CFX_BaseArray::AddSpaceTo(int32_t index) {
  ASSERT(index > -1);
  uint8_t*& pBuffer = m_pData->pBuffer;
  int32_t& iTotalCount = m_pData->iTotalCount;
  int32_t iBlockSize = m_pData->iBlockSize;
  if (index >= iTotalCount) {
    int32_t iGrowSize = m_pData->iGrowSize;
    iTotalCount = (index / iGrowSize + 1) * iGrowSize;
    int32_t iNewSize = iTotalCount * iBlockSize;
    if (!pBuffer) {
      pBuffer = FX_Alloc(uint8_t, iNewSize);
    } else {
      pBuffer = FX_Realloc(uint8_t, pBuffer, iNewSize);
    }
  }
  int32_t& iBlockCount = m_pData->iBlockCount;
  if (index >= iBlockCount) {
    iBlockCount = index + 1;
  }
  return pBuffer + index * iBlockSize;
}
コード例 #8
0
ファイル: fde_render.cpp プロジェクト: andoma/pdfium
void CFDE_RenderContext::RenderText(IFDE_TextSet* pTextSet,
                                    FDE_HVISUALOBJ hText) {
  FXSYS_assert(m_pRenderDevice != NULL);
  FXSYS_assert(pTextSet != NULL && hText != NULL);
  IFX_Font* pFont = pTextSet->GetFont(hText);
  if (pFont == NULL) {
    return;
  }
  int32_t iCount = pTextSet->GetDisplayPos(hText, NULL, FALSE);
  if (iCount < 1) {
    return;
  }
  if (m_pSolidBrush == NULL) {
    m_pSolidBrush = (IFDE_SolidBrush*)IFDE_Brush::Create(FDE_BRUSHTYPE_Solid);
    if (m_pSolidBrush == NULL) {
      return;
    }
  }
  if (m_pCharPos == NULL) {
    m_pCharPos = FX_Alloc(FXTEXT_CHARPOS, iCount);
  } else if (m_iCharPosCount < iCount) {
    m_pCharPos = FX_Realloc(FXTEXT_CHARPOS, m_pCharPos, iCount);
  }
  if (m_iCharPosCount < iCount) {
    m_iCharPosCount = iCount;
  }
  iCount = pTextSet->GetDisplayPos(hText, m_pCharPos, FALSE);
  FX_FLOAT fFontSize = pTextSet->GetFontSize(hText);
  FX_ARGB dwColor = pTextSet->GetFontColor(hText);
  m_pSolidBrush->SetColor(dwColor);
  FDE_HDEVICESTATE hState;
  FX_BOOL bClip = ApplyClip(pTextSet, hText, hState);
  m_pRenderDevice->DrawString(m_pSolidBrush, pFont, m_pCharPos, iCount,
                              fFontSize, &m_Transform);
  if (bClip) {
    RestoreClip(hState);
  }
}
コード例 #9
0
ファイル: fpdf_page_func.cpp プロジェクト: gradescope/pdfium
FX_BOOL CPDF_Function::Init(CPDF_Object* pObj) {
  CPDF_Stream* pStream = pObj->AsStream();
  CPDF_Dictionary* pDict = pStream ? pStream->GetDict() : pObj->AsDictionary();

  CPDF_Array* pDomains = pDict->GetArrayBy("Domain");
  if (!pDomains)
    return FALSE;

  m_nInputs = pDomains->GetCount() / 2;
  if (m_nInputs == 0)
    return FALSE;

  m_pDomains = FX_Alloc2D(FX_FLOAT, m_nInputs, 2);
  for (uint32_t i = 0; i < m_nInputs * 2; i++) {
    m_pDomains[i] = pDomains->GetFloatAt(i);
  }
  CPDF_Array* pRanges = pDict->GetArrayBy("Range");
  m_nOutputs = 0;
  if (pRanges) {
    m_nOutputs = pRanges->GetCount() / 2;
    m_pRanges = FX_Alloc2D(FX_FLOAT, m_nOutputs, 2);
    for (uint32_t i = 0; i < m_nOutputs * 2; i++)
      m_pRanges[i] = pRanges->GetFloatAt(i);
  }
  uint32_t old_outputs = m_nOutputs;
  if (!v_Init(pObj))
    return FALSE;
  if (m_pRanges && m_nOutputs > old_outputs) {
    m_pRanges = FX_Realloc(FX_FLOAT, m_pRanges, m_nOutputs * 2);
    if (m_pRanges) {
      FXSYS_memset(m_pRanges + (old_outputs * 2), 0,
                   sizeof(FX_FLOAT) * (m_nOutputs - old_outputs) * 2);
    }
  }
  return TRUE;
}
コード例 #10
0
void CFDE_TxtEdtParag::LoadParag() {
  if (m_lpData) {
    m_lpData[0]++;
    return;
  }
  CFX_TxtBreak* pTxtBreak = m_pEngine->GetTextBreak();
  CFDE_TxtEdtBuf* pTxtBuf = m_pEngine->GetTextBuf();
  const FDE_TXTEDTPARAMS* pParam = m_pEngine->GetEditParams();
  FX_WCHAR wcAlias = 0;
  if (pParam->dwMode & FDE_TEXTEDITMODE_Password) {
    wcAlias = m_pEngine->GetAliasChar();
  }
  std::unique_ptr<IFX_CharIter> pIter(new CFDE_TxtEdtBuf::Iterator(
      static_cast<CFDE_TxtEdtBuf*>(pTxtBuf), wcAlias));
  pIter->SetAt(m_nCharStart);
  int32_t nEndIndex = m_nCharStart + m_nCharCount;
  CFX_ArrayTemplate<int32_t> LineBaseArr;
  bool bReload = false;
  uint32_t dwBreakStatus = FX_TXTBREAK_None;
  do {
    if (bReload) {
      dwBreakStatus = pTxtBreak->EndBreak(FX_TXTBREAK_ParagraphBreak);
    } else {
      FX_WCHAR wAppend = pIter->GetChar();
      dwBreakStatus = pTxtBreak->AppendChar(wAppend);
    }
    if (pIter->GetAt() + 1 == nEndIndex &&
        dwBreakStatus < FX_TXTBREAK_LineBreak) {
      dwBreakStatus = pTxtBreak->EndBreak(FX_TXTBREAK_ParagraphBreak);
    }
    if (dwBreakStatus > FX_TXTBREAK_PieceBreak) {
      int32_t nCount = pTxtBreak->CountBreakPieces();
      int32_t nTotal = 0;
      for (int32_t j = 0; j < nCount; j++) {
        const CFX_TxtPiece* Piece = pTxtBreak->GetBreakPiece(j);
        nTotal += Piece->GetLength();
      }
      LineBaseArr.Add(nTotal);
      pTxtBreak->ClearBreakPieces();
    }
    if ((pIter->GetAt() + 1 == nEndIndex) &&
        (dwBreakStatus == FX_TXTBREAK_LineBreak)) {
      bReload = true;
      pIter->Next(true);
    }
  } while (pIter->Next(false) && (pIter->GetAt() < nEndIndex));
  pTxtBreak->EndBreak(FX_TXTBREAK_ParagraphBreak);
  pTxtBreak->ClearBreakPieces();
  int32_t nLineCount = LineBaseArr.GetSize();
  m_nLineCount = nLineCount;
  if (m_lpData) {
    m_lpData = FX_Realloc(int32_t, m_lpData, nLineCount + 1);
  } else {
    m_lpData = FX_Alloc(int32_t, nLineCount + 1);
  }
  int32_t* pIntArr = m_lpData;
  pIntArr[0] = 1;
  m_nLineCount = nLineCount;
  pIntArr++;
  for (int32_t j = 0; j < nLineCount; j++, pIntArr++) {
    *pIntArr = LineBaseArr[j];
  }
  LineBaseArr.RemoveAll();
}
コード例 #11
0
static void _JpegEncode(const CFX_DIBSource* pSource, FX_LPBYTE& dest_buf, FX_STRSIZE& dest_size, int quality, FX_LPCBYTE icc_buf, FX_DWORD icc_length)
{
    struct jpeg_error_mgr jerr;
    jerr.error_exit = _error_do_nothing;
    jerr.emit_message = _error_do_nothing1;
    jerr.output_message = _error_do_nothing;
    jerr.format_message = _error_do_nothing2;
    jerr.reset_error_mgr = _error_do_nothing;

    struct jpeg_compress_struct cinfo;
    memset(&cinfo, 0, sizeof(cinfo));
    cinfo.err = &jerr;
    jpeg_create_compress(&cinfo);
    int Bpp = pSource->GetBPP() / 8;
    FX_DWORD nComponents = Bpp >= 3 ? (pSource->IsCmykImage() ? 4 : 3) : 1;
    FX_DWORD pitch = pSource->GetPitch();
    FX_DWORD width = pdfium::base::checked_cast<FX_DWORD>(pSource->GetWidth());
    FX_DWORD height = pdfium::base::checked_cast<FX_DWORD>(pSource->GetHeight());
    FX_SAFE_DWORD safe_buf_len = width;
    safe_buf_len *= height;
    safe_buf_len *= nComponents;
    safe_buf_len += 1024;
    if (icc_length) {
        safe_buf_len += 255 * 18;
        safe_buf_len += icc_length;
    }
    FX_DWORD dest_buf_length = 0;
    if (!safe_buf_len.IsValid()) {
        dest_buf = nullptr;
    } else {
        dest_buf_length = safe_buf_len.ValueOrDie();
        dest_buf = FX_TryAlloc(FX_BYTE, dest_buf_length);
        const int MIN_TRY_BUF_LEN = 1024;
        while (!dest_buf && dest_buf_length > MIN_TRY_BUF_LEN) {
            dest_buf_length >>= 1;
            dest_buf = FX_TryAlloc(FX_BYTE, dest_buf_length);
        }
    }
    if (!dest_buf) {
        FX_OutOfMemoryTerminate(); 
    }
    struct jpeg_destination_mgr dest;
    dest.init_destination = _dest_do_nothing;
    dest.term_destination = _dest_do_nothing;
    dest.empty_output_buffer = _dest_empty;
    dest.next_output_byte = dest_buf;
    dest.free_in_buffer = dest_buf_length;
    cinfo.dest = &dest;
    cinfo.image_width = width;
    cinfo.image_height = height;
    cinfo.input_components = nComponents;
    if (nComponents == 1) {
        cinfo.in_color_space = JCS_GRAYSCALE;
    } else if (nComponents == 3) {
        cinfo.in_color_space = JCS_RGB;
    } else {
        cinfo.in_color_space = JCS_CMYK;
    }
    FX_LPBYTE line_buf = NULL;
    if (nComponents > 1) {
        line_buf = FX_Alloc2D(FX_BYTE, width, nComponents);
    }
    jpeg_set_defaults(&cinfo);
    if(quality != 75) {
        jpeg_set_quality(&cinfo, quality, TRUE);
    }
    jpeg_start_compress(&cinfo, TRUE);
    _JpegEmbedIccProfile(&cinfo, icc_buf, icc_length);
    JSAMPROW row_pointer[1];
    JDIMENSION row;
    while (cinfo.next_scanline < cinfo.image_height) {
        FX_LPCBYTE src_scan = pSource->GetScanline(cinfo.next_scanline);
        if (nComponents > 1) {
            FX_LPBYTE dest_scan = line_buf;
            if (nComponents == 3) {
                for (int i = 0; i < width; i ++) {
                    dest_scan[0] = src_scan[2];
                    dest_scan[1] = src_scan[1];
                    dest_scan[2] = src_scan[0];
                    dest_scan += 3;
                    src_scan += Bpp;
                }
            } else {
                for (int i = 0; i < pitch; i ++) {
                    *dest_scan++ = ~*src_scan++;
                }
            }
            row_pointer[0] = line_buf;
        } else {
            row_pointer[0] = (FX_LPBYTE)src_scan;
        }
        row = cinfo.next_scanline;
        jpeg_write_scanlines(&cinfo, row_pointer, 1);
        if (cinfo.next_scanline == row) {
            dest_buf = FX_Realloc(FX_BYTE, dest_buf, dest_buf_length + JPEG_BLOCK_SIZE);
            dest.next_output_byte = dest_buf + dest_buf_length - dest.free_in_buffer;
            dest_buf_length += JPEG_BLOCK_SIZE;
            dest.free_in_buffer += JPEG_BLOCK_SIZE;
        }
    }
    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
    if (line_buf) {
        FX_Free(line_buf);
    }
    dest_size = dest_buf_length - (FX_STRSIZE)dest.free_in_buffer;
}
コード例 #12
0
FX_BOOL CFDE_GdiDevice::DrawString(IFDE_Brush* pBrush,
                                   IFX_Font* pFont,
                                   const FXTEXT_CHARPOS* pCharPos,
                                   int32_t iCount,
                                   FX_FLOAT fFontSize,
                                   const CFX_Matrix* pMatrix) {
  FXSYS_assert(pBrush != NULL && pFont != NULL && pCharPos != NULL);
  FX_ARGB argb = 0xFF000000;
  if (pBrush->GetType() == FDE_BRUSHTYPE_Solid) {
    argb = ((IFDE_SolidBrush*)pBrush)->GetColor();
  }
  CFDE_GdiFont* pGdiFont = (CFDE_GdiFont*)pFont;
  GLYPHMETRICS gm;
  MAT2 mat2;
  FX_FLOAT fScale = fFontSize / 1000.0f;
  FX_FLOAT ma, mb, mc, md;
  FX_FLOAT fx, fy;
  while (--iCount >= 0) {
    mb = mc = 0;
    ma = md = fScale;
    if (pCharPos->m_bGlyphAdjust) {
      FX_FLOAT aa =
          ma * -pCharPos->m_AdjustMatrix[0] + mb * pCharPos->m_AdjustMatrix[2];
      FX_FLOAT bb =
          -ma * pCharPos->m_AdjustMatrix[1] + mb * pCharPos->m_AdjustMatrix[3];
      FX_FLOAT cc =
          mc * -pCharPos->m_AdjustMatrix[0] + md * pCharPos->m_AdjustMatrix[2];
      FX_FLOAT dd =
          -mc * pCharPos->m_AdjustMatrix[1] + md * pCharPos->m_AdjustMatrix[3];
      ma = aa;
      mb = bb;
      mc = cc;
      md = dd;
    }
    if (pMatrix) {
      FX_FLOAT aa = ma * pMatrix->a + mb * pMatrix->c;
      FX_FLOAT bb = ma * pMatrix->b + mb * pMatrix->d;
      FX_FLOAT cc = mc * pMatrix->a + md * pMatrix->c;
      FX_FLOAT dd = mc * pMatrix->b + md * pMatrix->d;
      ma = aa;
      mb = bb;
      mc = cc;
      md = dd;
    }
    *(long*)(&mat2.eM11) = (long)(ma * 65536);
    *(long*)(&mat2.eM21) = (long)(mb * 65536);
    *(long*)(&mat2.eM12) = (long)(mc * 65536);
    *(long*)(&mat2.eM22) = (long)(md * 65536);
    FX_DWORD dwSize = pGdiFont->GetGlyphDIBits(pCharPos->m_GlyphIndex, argb,
                                               &mat2, gm, NULL, 0);
    if (dwSize > 0) {
      if (m_pGlyphBuf == NULL) {
        m_pGlyphBuf = FX_Alloc(uint8_t, dwSize);
        m_dwGlyphLen = dwSize;
      } else if (m_dwGlyphLen < dwSize) {
        m_pGlyphBuf = FX_Realloc(uint8_t, m_pGlyphBuf, dwSize);
        m_dwGlyphLen = dwSize;
      }
      pGdiFont->GetGlyphDIBits(pCharPos->m_GlyphIndex, argb, &mat2, gm,
                               m_pGlyphBuf, m_dwGlyphLen);
      Gdiplus::Bitmap bmp(gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmBlackBoxX * 4,
                          PixelFormat32bppARGB, m_pGlyphBuf);
      if (pMatrix) {
        fx = pMatrix->a * pCharPos->m_OriginX +
             pMatrix->c * pCharPos->m_OriginY + pMatrix->e;
        fy = pMatrix->b * pCharPos->m_OriginX +
             pMatrix->d * pCharPos->m_OriginY + pMatrix->f;
      } else {
        fx = pCharPos->m_OriginX;
        fy = pCharPos->m_OriginY;
      }
      m_pGraphics->DrawImage(&bmp, (FXSYS_round(fx) + gm.gmptGlyphOrigin.x),
                             (FXSYS_round(fy) - gm.gmptGlyphOrigin.y));
    }
    pCharPos++;
  }
  return TRUE;
}
コード例 #13
0
ファイル: fx_codec_jpeg.cpp プロジェクト: codemonkey85/pdfium
static void _JpegEncode(const CFX_DIBSource* pSource, FX_LPBYTE& dest_buf, FX_STRSIZE& dest_size, int quality, FX_LPCBYTE icc_buf, FX_DWORD icc_length)
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    jerr.error_exit = _error_do_nothing;
    jerr.emit_message = _error_do_nothing1;
    jerr.output_message = _error_do_nothing;
    jerr.format_message = _error_do_nothing2;
    jerr.reset_error_mgr = _error_do_nothing;
    cinfo.err = &jerr;
    jpeg_create_compress(&cinfo);
    int Bpp = pSource->GetBPP() / 8;
    int nComponents = Bpp >= 3 ? (pSource->IsCmykImage() ? 4 : 3) : 1;
    int pitch = pSource->GetPitch();
    int width = pSource->GetWidth();
    int height = pSource->GetHeight();
    FX_DWORD dest_buf_length = width * height * nComponents + 1024 + (icc_length ? (icc_length + 255 * 18) : 0);
    dest_buf = FX_Alloc(FX_BYTE, dest_buf_length);
    while (dest_buf == NULL) {
        dest_buf_length >>= 1;
        dest_buf = FX_Alloc(FX_BYTE, dest_buf_length);
    }
    FXSYS_memset32(dest_buf, 0, dest_buf_length);
    struct jpeg_destination_mgr dest;
    dest.init_destination = _dest_do_nothing;
    dest.term_destination = _dest_do_nothing;
    dest.empty_output_buffer = _dest_empty;
    dest.next_output_byte = dest_buf;
    dest.free_in_buffer = dest_buf_length;
    cinfo.dest = &dest;
    cinfo.image_width = width;
    cinfo.image_height = height;
    cinfo.input_components = nComponents;
    if (nComponents == 1) {
        cinfo.in_color_space = JCS_GRAYSCALE;
    } else if (nComponents == 3) {
        cinfo.in_color_space = JCS_RGB;
    } else {
        cinfo.in_color_space = JCS_CMYK;
    }
    FX_LPBYTE line_buf = NULL;
    if (nComponents > 1) {
        line_buf = FX_Alloc(FX_BYTE, width * nComponents);
        if (line_buf == NULL) {
            return;
        }
    }
    jpeg_set_defaults(&cinfo);
    if(quality != 75) {
        jpeg_set_quality(&cinfo, quality, TRUE);
    }
    jpeg_start_compress(&cinfo, TRUE);
    _JpegEmbedIccProfile(&cinfo, icc_buf, icc_length);
    JSAMPROW row_pointer[1];
    JDIMENSION row;
    while (cinfo.next_scanline < cinfo.image_height) {
        FX_LPCBYTE src_scan = pSource->GetScanline(cinfo.next_scanline);
        if (nComponents > 1) {
            FX_LPBYTE dest_scan = line_buf;
            if (nComponents == 3) {
                for (int i = 0; i < width; i ++) {
                    dest_scan[0] = src_scan[2];
                    dest_scan[1] = src_scan[1];
                    dest_scan[2] = src_scan[0];
                    dest_scan += 3;
                    src_scan += Bpp;
                }
            } else {
                for (int i = 0; i < pitch; i ++) {
                    *dest_scan++ = ~*src_scan++;
                }
            }
            row_pointer[0] = line_buf;
        } else {
            row_pointer[0] = (FX_LPBYTE)src_scan;
        }
        row = cinfo.next_scanline;
        jpeg_write_scanlines(&cinfo, row_pointer, 1);
        if (cinfo.next_scanline == row) {
            dest_buf = FX_Realloc(FX_BYTE, dest_buf, dest_buf_length + JPEG_BLOCK_SIZE);
            if (dest_buf == NULL) {
                FX_Free(line_buf);
                return;
            }
            dest.next_output_byte = dest_buf + dest_buf_length - dest.free_in_buffer;
            dest_buf_length += JPEG_BLOCK_SIZE;
            dest.free_in_buffer += JPEG_BLOCK_SIZE;
        }
    }
    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
    if (line_buf) {
        FX_Free(line_buf);
    }
    dest_size = dest_buf_length - (FX_STRSIZE)dest.free_in_buffer;
}