2015-07-22 2 views
1

Я работаю над написанием отчета из базы данных SQL (Windows SQL Server), в которой некоторые люди должны подписывать отчет перед отправкой его клиенту. Мы надеемся создать систему, в которой эти люди могут разрешить свою подпись в базе данных, а затем мы можем использовать образ своей подписи, хранящийся в базе данных, и поместить его в отчет, созданный LaTeX.Восстановить PNG-файл, сохраненный как RAW в базе данных SQL

Изображения подписи создаются как PNG, а затем сохраняются в базе данных в поле с типом varbinary. Чтобы использовать подпись в отчете, мне нужно восстановить PNG в файл, который я могу с \includegraphics в LaTeX.

К сожалению, я не могу воссоздать PNG из базы данных. Поскольку я не могу опубликовать подпись, мы будем использовать изображение ниже в качестве примера.

enter image description here

С помощью этого образа на моем компьютере, я могу прочитать файл как сырье, записать его в другой файл, и получить тот же образ, когда я открываю новый файл.

#* It works to read the image from a file and rewrite it elsewhere 
pal <- readBin("C:/[filepath]/ColorPalette.png", 
      what = "raw", n = 1e8) 
writeBin(pal, 
     "C:/[filepath]/colors.png", 
     useBytes=TRUE) 

Теперь я сохранил, что же изображение в базу данных, и с помощью RODBC, я могу извлечь его следующим образом:

#*** Capture the raw from the database 
con <- odbcConnect("DATABASE") 
Users <- sqlQuery(con, "SELECT * FROM dbo.[User]") 

db_pal <- Users$Signature[Users$LastName == "MyName"] 

#*** Write db_pal to a file, but the image won't render 
#*** Window Photo Viewer can't open this picture because the file appears to be damaged, corrupted, or is too large (12KB) 

writeBin(db_pal[[1]], 
     "C:/[filename]/db_colors.png", 
     useBytes=TRUE) 

Объекты pal и db_pal определены здесь в this Gist (они слишком длинны, чтобы вместиться в допустимое пространство здесь)

Примечание: db_pal - это список одного необработанного вектора. Кроме того, он явно отличается от исходного вектора pal

> length(pal) 
[1] 2471 
> length(db_pal[[1]]) 
[1] 9951 

Любые мысли о том, что я, возможно, нужно сделать, чтобы получить это изображение из базы данных?

+0

Вы знаете размеры вашего изображения (строки по столбцам)? –

+0

587 пикселей широкий - 496 пикселей. – Benjamin

ответ

1

Ну, мы выяснили решение. Необработанный вектор, возвращаемый через RODBC, не соответствовал тому, что было в базе данных SQL. Где-то в конвейере объект varbinary из SQL искажался. Я не знаю, почему и как. Но this answer to a different problem вдохновил нас переделать переменные. Как только мы их переработаем, мы увидим правильное представление.

Следующая проблема заключалась в том, что все наши изображения составляют более 8000 байт, а RODBC допускает только 8000 символов за раз. Поэтому мне пришлось пробираться по этому пути. Приведенный ниже код выполняет следующие действия:

  1. Определить наибольшее число байтов в файле изображения
  2. Создать набор переменных (ImagePart1, ..., ImagePart[n]) ломая изображение на столько частей, сколько необходимо, каждая с максимальной длиной 8000.
  3. Запросить базу данных для всех изображений.
  4. Объединение частей изображения в один объект
  5. Запишите изображения в локальный файл.

Фактический код

library(RODBC) 

lims <- odbcConnect("DATABASE") 

#* 1. Determine the largest number of bytes in the largest image file 
ImageLength <- sqlQuery(lims, 
          paste0("SELECT MaxLength = MAX(LEN(u.Image)) ", 
            "FROM dbo.[User] u")) 

#* Create a query string to make a set of variables breaking 
#* the images into as many parts as necessary, each with 
#* max length 8000 
n_img_vars <- ImageLength$MaxLength %/% 8000 + 1 

start <- 1 + 8000 * (0:(n_sig_vars - 1)) 
end <- 8000 + 8000 * (0:(n_sig_vars - 1)) 

img_parts <- paste0("ImagePart", 1:n_img_vars, 
        " = CAST(SUBSTRING(u.Image, ", start, 
        ", ", end, ") AS VARBINARY(8000))") 

full_query <- paste0("SELECT u.OID, u.LastName, u.FirstName,\n", 
        paste0(sig_parts, collapse =",\n"), "\n", 
        "FROM dbo.[User] u \n", 
        "WHERE LEN(u.Image) > 0") 

#* 3. Query the database for all the images 
Images <- sqlQuery(lims, full_query) 

#* 4. Combine the images parts into a single object 
Images$full_image <- 
    apply(Images[, grepl("ImagePart", names(Images))], 1, 
     function(x) do.call("c", x)) 

#* 5. Write the images to a local file 
for(i in seq_len(nrow(Images))){ 
    DIR <- "[FILE_DIR]" 
    FILENAME <- with(Images, paste0(OID[i], "-", LastName[i], ".png")) 
    writeBin(unlist(Images$full_image[i]), 
      file.path(DIR, FILENAME)) 
} 
0

Возможно, я неверно истолковал вопрос, но возможно, что пакет raster должен помочь вам.

library(raster) 
your_image <- raster(nrows=587,ncols=496,values=db_pal[[1]]) 
plot(your_image) 

Но это не имеет смысла, что длина db_pal[[1]] не 291152 (587 * 496), так что-то не добавляет для меня. Знаете ли вы, где эти 291,152 значения будут сохранены?